From 177d5fab289ad4ad8c8fc0e3b00667a9260c47ce Mon Sep 17 00:00:00 2001 From: EliverLara Date: Fri, 7 Aug 2020 13:54:28 -0500 Subject: [PATCH] KDE: Improve lockscreen to match sddm --- .../contents/components/ActionButton.qml | 128 ++++ .../contents/components/Battery.qml | 53 ++ .../contents/components/Clock.qml | 50 ++ .../components/KeyboardLayoutButton.qml | 52 ++ .../components/SessionManagementScreen.qml | 121 ++++ .../contents/components/UserDelegate.qml | 194 ++++++ .../contents/components/UserList.qml | 93 +++ .../contents/components/VirtualKeyboard.qml | 28 + .../contents/components/WallpaperFader.qml | 205 +++++++ .../contents/components/artwork/README.txt | 1 + .../components/artwork/logout_primary.svgz | Bin 0 -> 2514 bytes .../components/artwork/restart_primary.svgz | Bin 0 -> 1860 bytes .../components/artwork/shutdown_primary.svgz | Bin 0 -> 1738 bytes .../contents/lockscreen/LockOsd.qml | 83 +++ .../contents/lockscreen/LockScreen.qml | 65 ++ .../contents/lockscreen/LockScreenUi.qml | 578 ++++++++++++++++++ .../contents/lockscreen/MainBlock.qml | 143 +++++ .../contents/lockscreen/MediaControls.qml | 162 +++++ .../contents/lockscreen/config.qml | 44 ++ .../contents/lockscreen/config.xml | 19 + kde/look-and-feel/contents/osd/Osd.qml | 44 ++ kde/look-and-feel/contents/osd/OsdItem.qml | 87 +++ 22 files changed, 2150 insertions(+) create mode 100644 kde/look-and-feel/contents/components/ActionButton.qml create mode 100644 kde/look-and-feel/contents/components/Battery.qml create mode 100644 kde/look-and-feel/contents/components/Clock.qml create mode 100644 kde/look-and-feel/contents/components/KeyboardLayoutButton.qml create mode 100644 kde/look-and-feel/contents/components/SessionManagementScreen.qml create mode 100644 kde/look-and-feel/contents/components/UserDelegate.qml create mode 100644 kde/look-and-feel/contents/components/UserList.qml create mode 100644 kde/look-and-feel/contents/components/VirtualKeyboard.qml create mode 100644 kde/look-and-feel/contents/components/WallpaperFader.qml create mode 100644 kde/look-and-feel/contents/components/artwork/README.txt create mode 100644 kde/look-and-feel/contents/components/artwork/logout_primary.svgz create mode 100644 kde/look-and-feel/contents/components/artwork/restart_primary.svgz create mode 100644 kde/look-and-feel/contents/components/artwork/shutdown_primary.svgz create mode 100644 kde/look-and-feel/contents/lockscreen/LockOsd.qml create mode 100644 kde/look-and-feel/contents/lockscreen/LockScreen.qml create mode 100644 kde/look-and-feel/contents/lockscreen/LockScreenUi.qml create mode 100644 kde/look-and-feel/contents/lockscreen/MainBlock.qml create mode 100644 kde/look-and-feel/contents/lockscreen/MediaControls.qml create mode 100644 kde/look-and-feel/contents/lockscreen/config.qml create mode 100644 kde/look-and-feel/contents/lockscreen/config.xml create mode 100644 kde/look-and-feel/contents/osd/Osd.qml create mode 100644 kde/look-and-feel/contents/osd/OsdItem.qml diff --git a/kde/look-and-feel/contents/components/ActionButton.qml b/kde/look-and-feel/contents/components/ActionButton.qml new file mode 100644 index 0000000..7a66c56 --- /dev/null +++ b/kde/look-and-feel/contents/components/ActionButton.qml @@ -0,0 +1,128 @@ +/* + * Copyright 2016 David Edmundson + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.8 +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 2.0 as PlasmaComponents + +Item { + id: root + property alias text: label.text + property alias iconSource: icon.source + property alias containsMouse: mouseArea.containsMouse + property alias font: label.font + property alias labelRendering: label.renderType + property alias circleOpacity: iconCircle.opacity + property alias circleVisiblity: iconCircle.visible + property int fontSize: config.fontSize + readonly property bool softwareRendering: GraphicsInfo.api === GraphicsInfo.Software + signal clicked + + activeFocusOnTab: true + + property int iconSize: units.gridUnit * 3 + + implicitWidth: Math.max(iconSize + units.largeSpacing * 2, label.contentWidth) + implicitHeight: iconSize + units.smallSpacing + label.implicitHeight + + opacity: activeFocus || containsMouse ? 1 : 0.85 + Behavior on opacity { + PropertyAnimation { // OpacityAnimator makes it turn black at random intervals + duration: units.longDuration + easing.type: Easing.InOutQuad + } + } + + Rectangle { + id: iconCircle + anchors.centerIn: icon + width: iconSize + units.smallSpacing + height: width + radius: width / 2 + color: softwareRendering ? PlasmaCore.ColorScope.backgroundColor : PlasmaCore.ColorScope.textColor + opacity: activeFocus || containsMouse ? (softwareRendering ? 0.8 : 0.15) : (softwareRendering ? 0.6 : 0) + Behavior on opacity { + PropertyAnimation { // OpacityAnimator makes it turn black at random intervals + duration: units.longDuration + easing.type: Easing.InOutQuad + } + } + } + + Rectangle { + anchors.centerIn: iconCircle + width: iconCircle.width + height: width + radius: width / 2 + scale: mouseArea.containsPress ? 1 : 0 + color: PlasmaCore.ColorScope.textColor + opacity: 0.15 + Behavior on scale { + PropertyAnimation { + duration: units.shortDuration + easing.type: Easing.InOutQuart + } + } + } + + PlasmaCore.IconItem { + id: icon + anchors { + top: parent.top + horizontalCenter: parent.horizontalCenter + } + width: iconSize + height: iconSize + + colorGroup: PlasmaCore.ColorScope.colorGroup + active: mouseArea.containsMouse || root.activeFocus + } + + PlasmaComponents.Label { + id: label + font.pointSize: Math.max(fontSize + 1,theme.defaultFont.pointSize + 1) + anchors { + top: icon.bottom + topMargin: (softwareRendering ? 1.5 : 1) * units.smallSpacing + left: parent.left + right: parent.right + } + style: softwareRendering ? Text.Outline : Text.Normal + styleColor: softwareRendering ? PlasmaCore.ColorScope.backgroundColor : "transparent" //no outline, doesn't matter + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignTop + wrapMode: Text.WordWrap + font.underline: root.activeFocus + } + + MouseArea { + id: mouseArea + hoverEnabled: true + onClicked: root.clicked() + anchors.fill: parent + } + + Keys.onEnterPressed: clicked() + Keys.onReturnPressed: clicked() + Keys.onSpacePressed: clicked() + + Accessible.onPressAction: clicked() + Accessible.role: Accessible.Button + Accessible.name: label.text +} diff --git a/kde/look-and-feel/contents/components/Battery.qml b/kde/look-and-feel/contents/components/Battery.qml new file mode 100644 index 0000000..2351c4d --- /dev/null +++ b/kde/look-and-feel/contents/components/Battery.qml @@ -0,0 +1,53 @@ +/* + * Copyright 2016 Kai Uwe Broulik + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.2 + +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 2.0 as PlasmaComponents +import org.kde.plasma.workspace.components 2.0 as PW + +Row { + spacing: units.smallSpacing + visible: pmSource.data["Battery"]["Has Cumulative"] + + PlasmaCore.DataSource { + id: pmSource + engine: "powermanagement" + connectedSources: ["Battery", "AC Adapter"] + } + + PW.BatteryIcon { + id: battery + hasBattery: pmSource.data["Battery"]["Has Battery"] || false + percent: pmSource.data["Battery"]["Percent"] || 0 + pluggedIn: pmSource.data["AC Adapter"] ? pmSource.data["AC Adapter"]["Plugged in"] : false + + height: batteryLabel.height + width: height + } + + PlasmaComponents.Label { + id: batteryLabel + font.pointSize: config.fontSize + height: undefined + text: i18nd("plasma_lookandfeel_org.kde.lookandfeel","%1%", battery.percent) + Accessible.name: i18nd("plasma_lookandfeel_org.kde.lookandfeel","Battery at %1%", battery.percent) + } +} diff --git a/kde/look-and-feel/contents/components/Clock.qml b/kde/look-and-feel/contents/components/Clock.qml new file mode 100644 index 0000000..14bea3b --- /dev/null +++ b/kde/look-and-feel/contents/components/Clock.qml @@ -0,0 +1,50 @@ +/* + * Copyright 2016 David Edmundson + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.8 +import QtQuick.Layouts 1.1 +import QtQuick.Controls 2.5 +import org.kde.plasma.core 2.0 + +ColumnLayout { + readonly property bool softwareRendering: GraphicsInfo.api === GraphicsInfo.Software + + Label { + text: Qt.formatTime(timeSource.data["Local"]["DateTime"]) + color: ColorScope.textColor + style: softwareRendering ? Text.Outline : Text.Normal + styleColor: softwareRendering ? ColorScope.backgroundColor : "transparent" //no outline, doesn't matter + font.pointSize: 34 + Layout.alignment: Qt.AlignHCenter + } + Label { + text: Qt.formatDate(timeSource.data["Local"]["DateTime"], Qt.DefaultLocaleLongDate) + color: ColorScope.textColor + style: softwareRendering ? Text.Outline : Text.Normal + styleColor: softwareRendering ? ColorScope.backgroundColor : "transparent" //no outline, doesn't matter + font.pointSize: 17 + Layout.alignment: Qt.AlignHCenter + } + DataSource { + id: timeSource + engine: "time" + connectedSources: ["Local"] + interval: 1000 + } +} diff --git a/kde/look-and-feel/contents/components/KeyboardLayoutButton.qml b/kde/look-and-feel/contents/components/KeyboardLayoutButton.qml new file mode 100644 index 0000000..32edb52 --- /dev/null +++ b/kde/look-and-feel/contents/components/KeyboardLayoutButton.qml @@ -0,0 +1,52 @@ +/*************************************************************************** + * Copyright (C) 2014 by Daniel Vrátil * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * + ***************************************************************************/ + +import QtQuick 2.1 +import QtQuick.Controls 1.1 as QQC + +import org.kde.plasma.components 2.0 as PlasmaComponents + +import org.kde.plasma.workspace.keyboardlayout 1.0 + +PlasmaComponents.ToolButton { + + property int fontSize: config.fontSize + + id: kbLayoutButton + + iconName: "input-keyboard" + implicitWidth: minimumWidth + text: layout.currentLayoutDisplayName + font.pointSize: Math.max(fontSize,theme.defaultFont.pointSize) + + Accessible.name: i18ndc("plasma_lookandfeel_org.kde.lookandfeel", "Button to change keyboard layout", "Switch layout") + + visible: layout.layouts.length > 1 + + onClicked: layout.nextLayout() + + KeyboardLayout { + id: layout + function nextLayout() { + var layouts = layout.layouts; + var index = (layouts.indexOf(layout.currentLayout)+1) % layouts.length; + layout.currentLayout = layouts[index]; + } + } +} diff --git a/kde/look-and-feel/contents/components/SessionManagementScreen.qml b/kde/look-and-feel/contents/components/SessionManagementScreen.qml new file mode 100644 index 0000000..5f88260 --- /dev/null +++ b/kde/look-and-feel/contents/components/SessionManagementScreen.qml @@ -0,0 +1,121 @@ +/* + * Copyright 2016 David Edmundson + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.2 + +import QtQuick.Layouts 1.1 +import QtQuick.Controls 1.1 + +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 2.0 as PlasmaComponents + +Item { + id: root + + /* + * Any message to be displayed to the user, visible above the text fields + */ + property alias notificationMessage: notificationsLabel.text + + /* + * A list of Items (typically ActionButtons) to be shown in a Row beneath the prompts + */ + property alias actionItems: actionItemsLayout.children + + /* + * A model with a list of users to show in the view + * The following roles should exist: + * - name + * - iconSource + * + * The following are also handled: + * - vtNumber + * - displayNumber + * - session + * - isTty + */ + property alias userListModel: userListView.model + + /* + * Self explanatory + */ + property alias userListCurrentIndex: userListView.currentIndex + property var userListCurrentModelData: userListView.currentItem === null ? [] : userListView.currentItem.m + property bool showUserList: true + + property alias userList: userListView + + property int fontSize: config.fontSize + + default property alias _children: innerLayout.children + + UserList { + id: userListView + visible: showUserList && y > 0 + anchors { + bottom: parent.verticalCenter + left: parent.left + right: parent.right + } + } + + //goal is to show the prompts, in ~16 grid units high, then the action buttons + //but collapse the space between the prompts and actions if there's no room + //ui is constrained to 16 grid units wide, or the screen + ColumnLayout { + id: prompts + anchors.top: parent.verticalCenter + anchors.topMargin: units.gridUnit * 0.5 + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + PlasmaComponents.Label { + id: notificationsLabel + font.pointSize: Math.max(fontSize + 1,theme.defaultFont.pointSize + 1) + Layout.maximumWidth: units.gridUnit * 16 + Layout.alignment: Qt.AlignHCenter + Layout.fillWidth: true + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.WordWrap + font.italic: true + } + ColumnLayout { + Layout.minimumHeight: implicitHeight + Layout.maximumHeight: units.gridUnit * 10 + Layout.maximumWidth: units.gridUnit * 16 + Layout.alignment: Qt.AlignHCenter + ColumnLayout { + id: innerLayout + Layout.alignment: Qt.AlignHCenter + Layout.fillWidth: true + } + Item { + Layout.fillHeight: true + } + } + Row { //deliberately not rowlayout as I'm not trying to resize child items + id: actionItemsLayout + spacing: units.largeSpacing / 2 + Layout.alignment: Qt.AlignHCenter + } + Item { + Layout.fillHeight: true + } + } +} diff --git a/kde/look-and-feel/contents/components/UserDelegate.qml b/kde/look-and-feel/contents/components/UserDelegate.qml new file mode 100644 index 0000000..44af90b --- /dev/null +++ b/kde/look-and-feel/contents/components/UserDelegate.qml @@ -0,0 +1,194 @@ +/* + * Copyright 2014 David Edmundson + * Copyright 2014 Aleix Pol Gonzalez + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.8 +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 2.0 as PlasmaComponents + +Item { + id: wrapper + + // If we're using software rendering, draw outlines instead of shadows + // See https://bugs.kde.org/show_bug.cgi?id=398317 + readonly property bool softwareRendering: GraphicsInfo.api === GraphicsInfo.Software + + property bool isCurrent: true + + readonly property var m: model + property string name + property string userName + property string avatarPath + property string iconSource + property bool constrainText: true + property alias nameFontSize: usernameDelegate.font.pointSize + property int fontSize: config.fontSize + signal clicked() + + property real faceSize: units.gridUnit * 7 + + opacity: isCurrent ? 1.0 : 0.5 + + Behavior on opacity { + OpacityAnimator { + duration: units.longDuration + } + } + + // Draw a translucent background circle under the user picture + Rectangle { + anchors.centerIn: imageSource + width: imageSource.width + 5 // Subtract to prevent fringing + height: width + radius: width / 2 + + gradient: Gradient { + GradientStop { position: 0.0; color: "#FEAC5E" } + GradientStop { position: 0.33; color: "#C779D0" } + GradientStop { position: 1.0; color: "#4BC0C8" } + } + } + + + Item { + id: imageSource + anchors { + bottom: usernameDelegate.top + bottomMargin: units.largeSpacing + horizontalCenter: parent.horizontalCenter + } + Behavior on width { + PropertyAnimation { + from: faceSize + duration: units.longDuration; + } + } + width: isCurrent ? faceSize : faceSize - units.largeSpacing + height: width + + //Image takes priority, taking a full path to a file, if that doesn't exist we show an icon + Image { + id: face + source: wrapper.avatarPath + sourceSize: Qt.size(faceSize, faceSize) + fillMode: Image.PreserveAspectCrop + anchors.fill: parent + } + + PlasmaCore.IconItem { + id: faceIcon + source: iconSource + visible: (face.status == Image.Error || face.status == Image.Null) + anchors.fill: parent + anchors.margins: units.gridUnit * 0.5 // because mockup says so... + colorGroup: PlasmaCore.ColorScope.colorGroup + } + } + + ShaderEffect { + anchors { + bottom: usernameDelegate.top + bottomMargin: units.largeSpacing + horizontalCenter: parent.horizontalCenter + } + + width: imageSource.width + height: imageSource.height + + supportsAtlasTextures: true + + property var source: ShaderEffectSource { + sourceItem: imageSource + // software rendering is just a fallback so we can accept not having a rounded avatar here + hideSource: wrapper.GraphicsInfo.api !== GraphicsInfo.Software + live: true // otherwise the user in focus will show a blurred avatar + } + + property var colorBorder: "#00000000" + + //draw a circle with an antialiased border + //innerRadius = size of the inner circle with contents + //outerRadius = size of the border + //blend = area to blend between two colours + //all sizes are normalised so 0.5 == half the width of the texture + + //if copying into another project don't forget to connect themeChanged to update() + //but in SDDM that's a bit pointless + fragmentShader: " + varying highp vec2 qt_TexCoord0; + uniform highp float qt_Opacity; + uniform lowp sampler2D source; + + uniform lowp vec4 colorBorder; + highp float blend = 0.01; + highp float innerRadius = 0.47; + highp float outerRadius = 0.49; + lowp vec4 colorEmpty = vec4(0.0, 0.0, 0.0, 0.0); + + void main() { + lowp vec4 colorSource = texture2D(source, qt_TexCoord0.st); + + highp vec2 m = qt_TexCoord0 - vec2(0.5, 0.5); + highp float dist = sqrt(m.x * m.x + m.y * m.y); + + if (dist < innerRadius) + gl_FragColor = colorSource; + else if (dist < innerRadius + blend) + gl_FragColor = mix(colorSource, colorBorder, ((dist - innerRadius) / blend)); + else if (dist < outerRadius) + gl_FragColor = colorBorder; + else if (dist < outerRadius + blend) + gl_FragColor = mix(colorBorder, colorEmpty, ((dist - outerRadius) / blend)); + else + gl_FragColor = colorEmpty ; + + gl_FragColor = gl_FragColor * qt_Opacity; + } + " + } + + PlasmaComponents.Label { + id: usernameDelegate + font.pointSize: Math.max(fontSize + 2,theme.defaultFont.pointSize + 2) + anchors { + bottom: parent.bottom + horizontalCenter: parent.horizontalCenter + } + height: implicitHeight // work around stupid bug in Plasma Components that sets the height + width: constrainText ? parent.width : implicitWidth + text: wrapper.name + style: softwareRendering ? Text.Outline : Text.Normal + styleColor: softwareRendering ? PlasmaCore.ColorScope.backgroundColor : "transparent" //no outline, doesn't matter + elide: Text.ElideRight + horizontalAlignment: Text.AlignHCenter + //make an indication that this has active focus, this only happens when reached with keyboard navigation + font.underline: wrapper.activeFocus + } + + MouseArea { + anchors.fill: parent + hoverEnabled: true + + onClicked: wrapper.clicked(); + } + + Accessible.name: name + Accessible.role: Accessible.Button + function accessiblePressAction() { wrapper.clicked() } +} diff --git a/kde/look-and-feel/contents/components/UserList.qml b/kde/look-and-feel/contents/components/UserList.qml new file mode 100644 index 0000000..a2d8508 --- /dev/null +++ b/kde/look-and-feel/contents/components/UserList.qml @@ -0,0 +1,93 @@ +/* + * Copyright 2014 David Edmundson + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.2 + +ListView { + id: view + readonly property string selectedUser: currentItem ? currentItem.userName : "" + readonly property int userItemWidth: units.gridUnit * 8 + readonly property int userItemHeight: units.gridUnit * 8 + + implicitHeight: userItemHeight + + activeFocusOnTab : true + + /* + * Signals that a user was explicitly selected + */ + signal userSelected; + + orientation: ListView.Horizontal + highlightRangeMode: ListView.StrictlyEnforceRange + + //centre align selected item (which implicitly centre aligns the rest + preferredHighlightBegin: width/2 - userItemWidth/2 + preferredHighlightEnd: preferredHighlightBegin + + delegate: UserDelegate { + avatarPath: model.icon || "" + iconSource: model.iconName || "user-identity" + + name: { + var displayName = model.realName || model.name + + if (model.vtNumber === undefined || model.vtNumber < 0) { + return displayName + } + + if (!model.session) { + return i18ndc("plasma_lookandfeel_org.kde.lookandfeel", "Nobody logged in on that session", "Unused") + } + + + var location = "" + if (model.isTty) { + location = i18ndc("plasma_lookandfeel_org.kde.lookandfeel", "User logged in on console number", "TTY %1", model.vtNumber) + } else if (model.displayNumber) { + location = i18ndc("plasma_lookandfeel_org.kde.lookandfeel", "User logged in on console (X display number)", "on TTY %1 (Display %2)", model.vtNumber, model.displayNumber) + } + + if (location) { + return i18ndc("plasma_lookandfeel_org.kde.lookandfeel", "Username (location)", "%1 (%2)", displayName, location) + } + + return displayName + } + + userName: model.name + + width: userItemWidth + height: userItemHeight + + //if we only have one delegate, we don't need to clip the text as it won't be overlapping with anything + constrainText: ListView.view.count > 1 + + isCurrent: ListView.isCurrentItem + + onClicked: { + ListView.view.currentIndex = index; + ListView.view.userSelected(); + } + } + + Keys.onEscapePressed: view.userSelected() + Keys.onEnterPressed: view.userSelected() + Keys.onReturnPressed: view.userSelected() +} diff --git a/kde/look-and-feel/contents/components/VirtualKeyboard.qml b/kde/look-and-feel/contents/components/VirtualKeyboard.qml new file mode 100644 index 0000000..7848b75 --- /dev/null +++ b/kde/look-and-feel/contents/components/VirtualKeyboard.qml @@ -0,0 +1,28 @@ +/******************************************************************** + This file is part of the KDE project. + +Copyright (C) 2017 Martin Gräßlin + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ +import QtQuick 2.5 +import QtQuick.VirtualKeyboard 2.1 + +InputPanel { + id: inputPanel + property bool activated: false + active: activated && Qt.inputMethod.visible + visible: active + width: parent.width +} diff --git a/kde/look-and-feel/contents/components/WallpaperFader.qml b/kde/look-and-feel/contents/components/WallpaperFader.qml new file mode 100644 index 0000000..768a9c1 --- /dev/null +++ b/kde/look-and-feel/contents/components/WallpaperFader.qml @@ -0,0 +1,205 @@ +/******************************************************************** + This file is part of the KDE project. + +Copyright (C) 2014 Aleix Pol Gonzalez + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ + +import QtQuick 2.6 +import QtQuick.Controls 1.1 +import QtQuick.Layouts 1.1 +import QtGraphicalEffects 1.0 + +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 2.0 as PlasmaComponents + +import org.kde.plasma.private.sessions 2.0 +import "../components" + +Item { + id: wallpaperFader + property Item clock + property Item mainStack + property Item footer + property Item formBg + property Item blurArea + property Item blur + property alias source: wallpaperBlur.source + state: lockScreenRoot.uiVisible ? "on" : "off" + property real factor: 0 + readonly property bool lightBackground: Math.max(PlasmaCore.ColorScope.backgroundColor.r, PlasmaCore.ColorScope.backgroundColor.g, PlasmaCore.ColorScope.backgroundColor.b) > 0.5 + + property bool alwaysShowClock: typeof config === "undefined" || config.alwaysShowClock === true + + Behavior on factor { + NumberAnimation { + target: wallpaperFader + property: "factor" + duration: 1000 + easing.type: Easing.InOutQuad + } + } + FastBlur { + id: wallpaperBlur + anchors.fill: parent + radius: 50 * wallpaperFader.factor + } + ShaderEffect { + id: wallpaperShader + anchors.fill: parent + supportsAtlasTextures: true + property var source: ShaderEffectSource { + sourceItem: wallpaperBlur + live: true + hideSource: true + textureMirroring: ShaderEffectSource.NoMirroring + } + + readonly property real contrast: 0.65 * wallpaperFader.factor + (1 - wallpaperFader.factor) + readonly property real saturation: 1.6 * wallpaperFader.factor + (1 - wallpaperFader.factor) + readonly property real intensity: (wallpaperFader.lightBackground ? 1.7 : 0.6) * wallpaperFader.factor + (1 - wallpaperFader.factor) + + readonly property real transl: (1.0 - contrast) / 2.0; + readonly property real rval: (1.0 - saturation) * 0.2126; + readonly property real gval: (1.0 - saturation) * 0.7152; + readonly property real bval: (1.0 - saturation) * 0.0722; + + property var colorMatrix: Qt.matrix4x4( + contrast, 0, 0, 0.0, + 0, contrast, 0, 0.0, + 0, 0, contrast, 0.0, + transl, transl, transl, 1.0).times(Qt.matrix4x4( + rval + saturation, rval, rval, 0.0, + gval, gval + saturation, gval, 0.0, + bval, bval, bval + saturation, 0.0, + 0, 0, 0, 1.0)).times(Qt.matrix4x4( + intensity, 0, 0, 0, + 0, intensity, 0, 0, + 0, 0, intensity, 0, + 0, 0, 0, 1 + )); + + + fragmentShader: " + uniform mediump mat4 colorMatrix; + uniform mediump sampler2D source; + varying mediump vec2 qt_TexCoord0; + uniform lowp float qt_Opacity; + + void main(void) + { + mediump vec4 tex = texture2D(source, qt_TexCoord0); + gl_FragColor = tex * colorMatrix * qt_Opacity; + }" + } + + states: [ + State { + name: "on" + PropertyChanges { + target: mainStack + opacity: 1 + } + PropertyChanges { + target: footer + opacity: 1 + } + PropertyChanges { + target: wallpaperFader + factor: 0 + } + PropertyChanges { + target: clock.shadow + opacity: 0 + } + PropertyChanges { + target: clock + opacity: 1 + anchors.horizontalCenter: formBg.horizontalCenter + // y: parent.height - height - 10 + } + PropertyChanges { + target: formBg + opacity: 0.5 + } + PropertyChanges { + target: blurArea + opacity: 1 + } + PropertyChanges { + target: blur + opacity: 1 + } + }, + State { + name: "off" + PropertyChanges { + target: mainStack + opacity: 0 + } + PropertyChanges { + target: footer + opacity: 0 + } + PropertyChanges { + target: wallpaperFader + factor: 0 + } + PropertyChanges { + target: clock.shadow + opacity: wallpaperFader.alwaysShowClock ? 1 : 0 + } + PropertyChanges { + target: clock + opacity: wallpaperFader.alwaysShowClock ? 1 : 0 + } + PropertyChanges { + target: formBg + opacity: 0 + } + PropertyChanges { + target: blurArea + opacity: 0 + } + PropertyChanges { + target: blur + opacity: 0 + } + } + ] + transitions: [ + Transition { + from: "off" + to: "on" + //Note: can't use animators as they don't play well with parallelanimations + NumberAnimation { + targets: [mainStack, footer, clock] + property: "opacity" + duration: units.longDuration + easing.type: Easing.InOutQuad + } + }, + Transition { + from: "on" + to: "off" + NumberAnimation { + targets: [mainStack, footer, clock] + property: "opacity" + duration: 500 + easing.type: Easing.InOutQuad + } + } + ] +} diff --git a/kde/look-and-feel/contents/components/artwork/README.txt b/kde/look-and-feel/contents/components/artwork/README.txt new file mode 100644 index 0000000..1885a36 --- /dev/null +++ b/kde/look-and-feel/contents/components/artwork/README.txt @@ -0,0 +1 @@ +After editing SVG files be sure to run currentColorFillFix.sh from plasma-framework \ No newline at end of file diff --git a/kde/look-and-feel/contents/components/artwork/logout_primary.svgz b/kde/look-and-feel/contents/components/artwork/logout_primary.svgz new file mode 100644 index 0000000000000000000000000000000000000000..6a9423faac82072f74efa510c57f762df3c5b6be GIT binary patch literal 2514 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 literal 0 HcmV?d00001 diff --git a/kde/look-and-feel/contents/components/artwork/shutdown_primary.svgz b/kde/look-and-feel/contents/components/artwork/shutdown_primary.svgz new file mode 100644 index 0000000000000000000000000000000000000000..1c60152f8cf5b181ae3a0722722ff5fe1d140982 GIT binary patch literal 1738 zcmb2|=HO6wU=3klF3u<|Ny#tIi!Uh3%uOt+)GIDaXIL73ck*ltq5Apzn^g5Z=dw=v zVPNqs=c>xoJ7IVC<`k9pM@yv4=JgN}O0Hh_u73YChDQ6e%~QWlIqh8kZ`ajVdDrac zzdBW!wpNGr{*EJu*B!3V>zef5{N4V2bxxhHJ*IwCTFsI!J)Qge^W*Jb{W&bduj{qgou zYKP($cFmk=IA1(Yf6|%Fvrej=p83Un*G2njtyTwqUOHkU7qQcR#mk*KW_k*J1vl)^ zb2WWoYTh{YX@b7bo(q|mO+0!}bX0|Q#2jYmZub*?bfP}{)~0i}HnZ!+-EkL)6VFlK z8uUKO-qqqz8~dHuNX={C{=_X>-XhViQKFm75}FzvmV1YPkx=f>LwT$VX6$OLpWit} zV5-*a-rpgHaTX2b=VdNhCH=NO9UA|5=H}Hc8gpW97e4T_n54P<(#j`3Ud|_3!*kW9 zmKHaK+-(2+C(%aOd&BZ1&11q^mPhV&aJ`BxxU!r{%m3f6pP46SoRc(u_}4f%w^HhB z`;)Vg6AnxGDm+-Tc~x@JyU^!pkLwJl{@i(Xmh;T>6|dHC2c)gae)#LWgzn^6)(^kq zUs?U*xuZUJXLdvzM}v?{dYR9piJY=MZ@1@Xwuqa=yn4S|+LG~V+^Wy2|GYJx2z6OL z%+_d=NNT#6D)&O^bEU>U4olJ-h4a5#H{oVLy zf4g;;f8@X1`(1tF=C^XTAGZF~e(S&9&5!M|*-z~Y_MiTGzg+iE?12qC9`8RP;k|$L zU(Y9V{|G)^?x%UM-sY{_-}S2dw|{*6@%yiOE#~a|A!{U8?VGpwnZ0%QR|UO!igPb- zxSLj_^MI}G&V}^*ES>+PC895it&xq~_%mk1vURU}Hy^ndo_qDvM)q5+!tq7Q9z4~O_F@t5@%CeJiJm^-CH^9$3gIO9aimtV3vt>Uy^ zB%OWfR=eXvXjz)T-k*}YciMD3-gh-JB=`6_(|*sB#+?Q7E(#7_ z&EYdPn?9Nqn!bEfo9v1iE@exZigxQ;=2)JMtvXuvN^kMo#(NKQSg&N%vUfa*Y~B`K zC^gB%B<%F{pS$18U%q)+Y!8<&hrzsM8mp!EUY~V+QYLeaUh2-ZH;xuI=$vnehzT@Z z=NK2g-s{Fqmi6btlaenU)^aGb_MRtdqL$e+-P7WD+SUigmzmDR7+6v){e(XjHY75a!a?Umb5>x2f3VeE5ICx7%-?U~kOPwz9Cd&i(po?)nF% zi_cwI99i^r_Nn_1zB27zTUuhb!RzC9r*BtU@4fa(ePC+n-$irJgv~pc zu~N(IcJm*`zZR3z53c=dSoL|!ey#0^-~YGoTgJCj&+YEv*>$nT;y33ORTXYbOn)Ba zzJ4|1zt+_Dy{;Sc;=E_+1$Z&#OI|doGhep<&sw$beTKg&XA z+pdth-IMwIy=m&5l<+5eL)QK{7AA9V$J%x4nADfW@pKey@;G^kL5VNU#}g+Bn!2VO5YwS@FcUhHpgvRuyXpb zKnr!p{-Xu_8aud{`q?sPS(tpAW>~P;m4$1i+R+=YVjsu-KtGKQxxSv*8ARw!HPv~BmqtZ90Sxfv3mM}PV zAM}wq?o`WGnSg@$GDA2;=;FI;wr0Kc&$4# zlK2W|>Uc`&1aO!XWHjnJraCNJ?3`SoFTQtkD;JOF3_snqr + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ + +import QtQuick 2.0 +import org.kde.plasma.core 2.0 as PlasmaCore +import "../osd" + +PlasmaCore.FrameSvgItem { + id: osd + + // OSD Timeout in msecs - how long it will stay on the screen + property int timeout: 1800 + // This is either a text or a number, if showingProgress is set to true, + // the number will be used as a value for the progress bar + property var osdValue + // Icon name to display + property string icon + // Set to true if the value is meant for progress bar, + // false for displaying the value as normal text + property bool showingProgress: false + + objectName: "onScreenDisplay" + visible: false + width: osdItem.width + margins.left + margins.right + height: osdItem.height + margins.top + margins.bottom + imagePath: "widgets/background" + + function show() { + osd.visible = true; + hideAnimation.restart(); + } + + // avoid leaking ColorScope of lock screen theme into the OSD "popup" + PlasmaCore.ColorScope { + width: osdItem.width + height: osdItem.height + anchors.centerIn: parent + colorGroup: PlasmaCore.Theme.NormalColorGroup + + OsdItem { + id: osdItem + rootItem: osd + } + } + + SequentialAnimation { + id: hideAnimation + // prevent press and hold from flickering + PauseAnimation { duration: 100 } + NumberAnimation { + target: osd + property: "opacity" + from: 1 + to: 0 + duration: osd.timeout + easing.type: Easing.InQuad + } + ScriptAction { + script: { + osd.visible = false; + osd.opacity = 1; + osd.icon = ""; + osd.osdValue = 0; + } + } + } +} diff --git a/kde/look-and-feel/contents/lockscreen/LockScreen.qml b/kde/look-and-feel/contents/lockscreen/LockScreen.qml new file mode 100644 index 0000000..c0bc939 --- /dev/null +++ b/kde/look-and-feel/contents/lockscreen/LockScreen.qml @@ -0,0 +1,65 @@ +/******************************************************************** + This file is part of the KDE project. + +Copyright (C) 2014 Aleix Pol Gonzalez + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ + +import QtQuick 2.5 +import QtQuick.Controls 1.1 +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.private.sessions 2.0 +import "../components" + +Item { + id: root + property bool viewVisible: false + property bool debug: false + property string notification + property int interfaceVersion: org_kde_plasma_screenlocker_greeter_interfaceVersion ? org_kde_plasma_screenlocker_greeter_interfaceVersion : 0 + signal clearPassword() + + LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft + LayoutMirroring.childrenInherit: true + + Loader { + id: mainLoader + anchors.fill: parent + opacity: 0 + onItemChanged: opacity = 1 + + focus: true + + Behavior on opacity { + OpacityAnimator { + duration: units.longDuration + easing.type: Easing.InCubic + } + } + } + Connections { + id:loaderConnection + target: org_kde_plasma_screenlocker_greeter_view + onFrameSwapped: { + mainLoader.source = "LockScreenUi.qml"; + loaderConnection.target = null; + } + } + Component.onCompleted: { + if (root.interfaceVersion < 2) { + mainLoader.source = "LockScreenUi.qml"; + } + } +} diff --git a/kde/look-and-feel/contents/lockscreen/LockScreenUi.qml b/kde/look-and-feel/contents/lockscreen/LockScreenUi.qml new file mode 100644 index 0000000..bf5accd --- /dev/null +++ b/kde/look-and-feel/contents/lockscreen/LockScreenUi.qml @@ -0,0 +1,578 @@ +/******************************************************************** + This file is part of the KDE project. + +Copyright (C) 2014 Aleix Pol Gonzalez + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ + +import QtQuick 2.8 +import QtQuick.Controls 1.1 +import QtQuick.Layouts 1.1 +import QtGraphicalEffects 1.0 + +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 2.0 as PlasmaComponents +import org.kde.plasma.extras 2.0 as PlasmaExtras + + +import org.kde.plasma.private.sessions 2.0 +import "../components" + +PlasmaCore.ColorScope { + + id: lockScreenUi + // If we're using software rendering, draw outlines instead of shadows + // See https://bugs.kde.org/show_bug.cgi?id=398317 + readonly property bool softwareRendering: GraphicsInfo.api === GraphicsInfo.Software + readonly property bool lightBackground: Math.max(PlasmaCore.ColorScope.backgroundColor.r, PlasmaCore.ColorScope.backgroundColor.g, PlasmaCore.ColorScope.backgroundColor.b) > 0.5 + + colorGroup: PlasmaCore.Theme.ComplementaryColorGroup + + Connections { + target: authenticator + onFailed: { + root.notification = i18nd("plasma_lookandfeel_org.kde.lookandfeel","Unlocking failed"); + } + onGraceLockedChanged: { + if (!authenticator.graceLocked) { + root.notification = ""; + root.clearPassword(); + } + } + onMessage: { + root.notification = msg; + } + onError: { + root.notification = err; + } + } + + SessionManagement { + id: sessionManagement + } + + Connections { + target: sessionManagement + onAboutToSuspend: { + mainBlock.mainPasswordBox.text = ""; + } + } + + SessionsModel { + id: sessionsModel + showNewSessionEntry: false + } + + PlasmaCore.DataSource { + id: keystateSource + engine: "keystate" + connectedSources: "Caps Lock" + } + + Loader { + id: changeSessionComponent + active: false + source: "ChangeSession.qml" + visible: false + } + + MouseArea { + id: lockScreenRoot + + property bool uiVisible: false + property bool blockUI: mainStack.depth > 1 || mainBlock.mainPasswordBox.text.length > 0 || inputPanel.keyboardActive + + x: parent.x + y: parent.y + width: parent.width + height: parent.height + hoverEnabled: true + drag.filterChildren: true + onPressed: uiVisible = true; + onPositionChanged: uiVisible = true; + onUiVisibleChanged: { + if (blockUI) { + fadeoutTimer.running = false; + } else if (uiVisible) { + fadeoutTimer.restart(); + } + } + onBlockUIChanged: { + if (blockUI) { + fadeoutTimer.running = false; + uiVisible = true; + } else { + fadeoutTimer.restart(); + } + } + Keys.onEscapePressed: { + uiVisible = !uiVisible; + if (inputPanel.keyboardActive) { + inputPanel.showHide(); + } + if (!uiVisible) { + mainBlock.mainPasswordBox.text = ""; + } + } + Keys.onPressed: { + uiVisible = true; + event.accepted = false; + } + Timer { + id: fadeoutTimer + interval: 10000 + onTriggered: { + if (!lockScreenRoot.blockUI) { + lockScreenRoot.uiVisible = false; + } + } + } + + Component.onCompleted: PropertyAnimation { id: launchAnimation; target: lockScreenRoot; property: "opacity"; from: 0; to: 1; duration: 1000 } + + states: [ + State { + name: "onOtherSession" + // for slide out animation + PropertyChanges { target: lockScreenRoot; y: lockScreenRoot.height } + // we also change the opacity just to be sure it's not visible even on unexpected screen dimension changes with possible race conditions + PropertyChanges { target: lockScreenRoot; opacity: 0 } + } + ] + + transitions: + Transition { + // we only animate switchting to another session, because kscreenlocker doesn't get notified when + // coming from another session back and so we wouldn't know when to trigger the animation exactly + from: "" + to: "onOtherSession" + + PropertyAnimation { id: stateChangeAnimation; properties: "y"; duration: 300; easing.type: Easing.InQuad} + PropertyAnimation { properties: "opacity"; duration: 300} + + onRunningChanged: { + // after the animation has finished switch session: since we only animate the transition TO state "onOtherSession" + // and not the other way around, we don't have to check the state we transitioned into + if (/* lockScreenRoot.state == "onOtherSession" && */ !running) { + mainStack.currentItem.switchSession() + } + } + } + + WallpaperFader { + anchors.fill: parent + state: lockScreenRoot.uiVisible ? "on" : "off" + source: wallpaper + mainStack: mainStack + footer: footer + clock: clock + formBg: formBg + blurArea: blurArea + blur: blur + z: -3 + } + + DropShadow { + id: clockShadow + anchors.fill: clock + source: clock + visible: !softwareRendering + horizontalOffset: 1 + verticalOffset: 1 + radius: 6 + samples: 14 + spread: 0.3 + color: lockScreenUi.lightBackground ? PlasmaCore.ColorScope.backgroundColor : "black" // black matches Breeze window decoration and desktopcontainment + Behavior on opacity { + OpacityAnimator { + duration: 1000 + easing.type: Easing.InOutQuad + } + } + } + + Clock { + id: clock + property Item shadow: clockShadow + anchors.horizontalCenter: parent.horizontalCenter + y: (mainBlock.userList.y + mainStack.y)/2 - height/2 + visible: y > 0 + Layout.alignment: Qt.AlignBaseline + } + + ListModel { + id: users + + Component.onCompleted: { + users.append({name: kscreenlocker_userName, + realName: kscreenlocker_userName, + icon: kscreenlocker_userImage, + + }) + } + } + + StackView { + id: mainStack + anchors.left: parent.left + + height: lockScreenRoot.height + units.gridUnit * 3 + width: parent.width / 3 + focus: true //StackView is an implicit focus scope, so we need to give this focus so the item inside will have it + + initialItem: MainBlock { + id: mainBlock + lockScreenUiVisible: lockScreenRoot.uiVisible + + showUserList: userList.y + mainStack.y > 0 + + Stack.onStatusChanged: { + // prepare for presenting again to the user + if (Stack.status == Stack.Activating) { + mainPasswordBox.remove(0, mainPasswordBox.length) + mainPasswordBox.focus = true + } + } + userListModel: users + notificationMessage: { + var text = "" + if (keystateSource.data["Caps Lock"]["Locked"]) { + text += i18nd("plasma_lookandfeel_org.kde.lookandfeel","Caps Lock is on") + if (root.notification) { + text += " • " + } + } + text += root.notification + return text + } + + onLoginRequest: { + root.notification = "" + authenticator.tryUnlock(password) + } + + actionItems: [ + ActionButton { + text: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Switch User") + iconSource: "system-switch-user" + onClicked: { + // If there are no existing sessions to switch to, create a new one instead + if (((sessionsModel.showNewSessionEntry && sessionsModel.count === 1) || + (!sessionsModel.showNewSessionEntry && sessionsModel.count === 0)) && + sessionsModel.canSwitchUser) { + mainStack.pop({immediate:true}) + sessionsModel.startNewSession(true /* lock the screen too */) + lockScreenRoot.state = '' + } else { + mainStack.push(switchSessionPage) + } + } + visible: sessionsModel.canStartNewSession && sessionsModel.canSwitchUser + //Button gets cut off on smaller displays without this. + anchors{ + verticalCenter: parent.top + } + } + ] + + Loader { + Layout.fillWidth: true + Layout.preferredHeight: item ? item.implicitHeight : 0 + active: config.showMediaControls + source: "MediaControls.qml" + } + } + + Component.onCompleted: { + if (defaultToSwitchUser) { //context property + // If we are in the only session, then going to the session switcher is + // a pointless extra step; instead create a new session immediately + if (((sessionsModel.showNewSessionEntry && sessionsModel.count === 1) || + (!sessionsModel.showNewSessionEntry && sessionsModel.count === 0)) && + sessionsModel.canStartNewSession) { + sessionsModel.startNewSession(true /* lock the screen too */) + } else { + mainStack.push({ + item: switchSessionPage, + immediate: true}); + } + } + } + } + + Loader { + id: inputPanel + state: "hidden" + readonly property bool keyboardActive: item ? item.active : false + anchors { + left: parent.left + right: parent.right + } + function showHide() { + state = state == "hidden" ? "visible" : "hidden"; + } + Component.onCompleted: inputPanel.source = "../components/VirtualKeyboard.qml" + + onKeyboardActiveChanged: { + if (keyboardActive) { + state = "visible"; + } else { + state = "hidden"; + } + } + + states: [ + State { + name: "visible" + PropertyChanges { + target: mainStack + y: Math.min(0, lockScreenRoot.height - inputPanel.height - mainBlock.visibleBoundary) + } + PropertyChanges { + target: inputPanel + y: lockScreenRoot.height - inputPanel.height + opacity: 1 + } + }, + State { + name: "hidden" + PropertyChanges { + target: mainStack + y: 0 + } + PropertyChanges { + target: inputPanel + y: lockScreenRoot.height - lockScreenRoot.height/4 + opacity: 0 + } + } + ] + transitions: [ + Transition { + from: "hidden" + to: "visible" + SequentialAnimation { + ScriptAction { + script: { + inputPanel.item.activated = true; + Qt.inputMethod.show(); + } + } + ParallelAnimation { + NumberAnimation { + target: mainStack + property: "y" + duration: units.longDuration + easing.type: Easing.InOutQuad + } + NumberAnimation { + target: inputPanel + property: "y" + duration: units.longDuration + easing.type: Easing.OutQuad + } + OpacityAnimator { + target: inputPanel + duration: units.longDuration + easing.type: Easing.OutQuad + } + } + } + }, + Transition { + from: "visible" + to: "hidden" + SequentialAnimation { + ParallelAnimation { + NumberAnimation { + target: mainStack + property: "y" + duration: units.longDuration + easing.type: Easing.InOutQuad + } + NumberAnimation { + target: inputPanel + property: "y" + duration: units.longDuration + easing.type: Easing.InQuad + } + OpacityAnimator { + target: inputPanel + duration: units.longDuration + easing.type: Easing.InQuad + } + } + ScriptAction { + script: { + Qt.inputMethod.hide(); + } + } + } + } + ] + } + + Component { + id: switchSessionPage + SessionManagementScreen { + property var switchSession: finalSwitchSession + + Stack.onStatusChanged: { + if (Stack.status == Stack.Activating) { + focus = true + } + } + + userListModel: sessionsModel + + // initiating animation of lockscreen for session switch + function initSwitchSession() { + lockScreenRoot.state = 'onOtherSession' + } + + // initiating session switch and preparing lockscreen for possible return of user + function finalSwitchSession() { + mainStack.pop({immediate:true}) + sessionsModel.switchUser(userListCurrentModelData.vtNumber) + lockScreenRoot.state = '' + } + + Keys.onLeftPressed: userList.decrementCurrentIndex() + Keys.onRightPressed: userList.incrementCurrentIndex() + Keys.onEnterPressed: initSwitchSession() + Keys.onReturnPressed: initSwitchSession() + Keys.onEscapePressed: mainStack.pop() + + ColumnLayout { + Layout.fillWidth: true + spacing: units.largeSpacing + + PlasmaComponents.Button { + Layout.fillWidth: true + font.pointSize: theme.defaultFont.pointSize + 1 + text: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Switch to This Session") + onClicked: initSwitchSession() + visible: sessionsModel.count > 0 + } + + PlasmaComponents.Button { + Layout.fillWidth: true + font.pointSize: theme.defaultFont.pointSize + 1 + text: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Start New Session") + onClicked: { + mainStack.pop({immediate:true}) + sessionsModel.startNewSession(true /* lock the screen too */) + lockScreenRoot.state = '' + } + } + } + + + actionItems: [ + ActionButton { + iconSource: "go-previous" + text: i18nd("plasma_lookandfeel_org.kde.lookandfeel","Back") + onClicked: mainStack.pop() + //Button gets cut off on smaller displays without this. + anchors{ + verticalCenter: parent.top + } + } + ] + } + } + + Rectangle { + id: formBg + anchors.fill: mainStack + anchors.centerIn: mainStack + color: "#161925" + opacity: 0.5 + z:-1 + } + + ShaderEffectSource { + id: blurArea + sourceItem: wallpaper + width: formBg.width + height: formBg.height + anchors.centerIn: formBg + sourceRect: Qt.rect(x,y,width,height) + visible: true + z:-2 + } + + GaussianBlur { + id: blur + height: formBg.height + width: formBg.width + source: blurArea + radius: 50 + samples: 50 * 2 + 1 + cached: true + anchors.centerIn: formBg + visible: true + z:-2 + } + + Loader { + active: root.viewVisible + source: "LockOsd.qml" + anchors { + horizontalCenter: parent.horizontalCenter + bottom: parent.bottom + bottomMargin: units.largeSpacing + } + } + + RowLayout { + id: footer + z: -2 + anchors { + bottom: parent.bottom + left: parent.left + right: parent.right + margins: units.smallSpacing + } + + Battery {} + + PlasmaComponents.ToolButton { + text: i18ndc("plasma_lookandfeel_org.kde.lookandfeel", "Button to show/hide virtual keyboard", "Virtual Keyboard") + iconName: inputPanel.keyboardActive ? "input-keyboard-virtual-on" : "input-keyboard-virtual-off" + onClicked: inputPanel.showHide() + + visible: inputPanel.status == Loader.Ready + } + + KeyboardLayoutButton { + } + + Item { + Layout.fillWidth: true + } + + + } + } + + Component.onCompleted: { + // version support checks + if (root.interfaceVersion < 1) { + // ksmserver of 5.4, with greeter of 5.5 + root.viewVisible = true; + } + } +} diff --git a/kde/look-and-feel/contents/lockscreen/MainBlock.qml b/kde/look-and-feel/contents/lockscreen/MainBlock.qml new file mode 100644 index 0000000..37f2a7a --- /dev/null +++ b/kde/look-and-feel/contents/lockscreen/MainBlock.qml @@ -0,0 +1,143 @@ +/* + * Copyright 2016 David Edmundson + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.8 +import QtQuick.Layouts 1.2 +import QtQuick.Controls 2.4 +import QtQuick.Controls.Styles 1.4 + +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 2.0 as PlasmaComponents + +import "../components" + +SessionManagementScreen { + + property Item mainPasswordBox: passwordBox + property bool lockScreenUiVisible: false + + //the y position that should be ensured visible when the on screen keyboard is visible + property int visibleBoundary: mapFromItem(loginButton, 0, 0).y + onHeightChanged: visibleBoundary = mapFromItem(loginButton, 0, 0).y + loginButton.height + units.smallSpacing + /* + * Login has been requested with the following username and password + * If username field is visible, it will be taken from that, otherwise from the "name" property of the currentIndex + */ + signal loginRequest(string password) + + function startLogin() { + var password = passwordBox.text + + //this is partly because it looks nicer + //but more importantly it works round a Qt bug that can trigger if the app is closed with a TextField focused + //See https://bugreports.qt.io/browse/QTBUG-55460 + loginButton.forceActiveFocus(); + loginRequest(password); + } + + RowLayout { + Layout.fillWidth: true + + TextField { + id: passwordBox + font.pointSize: theme.defaultFont.pointSize + 1 + Layout.fillWidth: true + placeholderText: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Password") + focus: true + echoMode: TextInput.Password + inputMethodHints: Qt.ImhHiddenText | Qt.ImhSensitiveData | Qt.ImhNoAutoUppercase | Qt.ImhNoPredictiveText + enabled: !authenticator.graceLocked + + placeholderTextColor: "#C3C7D1" + palette.text: "#C3C7D1" + + background: Rectangle { + color: "#161925" + opacity: 0.7 + radius: parent.width / 2 + height: 30 + width: 220 + anchors.centerIn: parent + } + + + onAccepted: { + if (lockScreenUiVisible) { + startLogin(); + } + } + + //if empty and left or right is pressed change selection in user switch + //this cannot be in keys.onLeftPressed as then it doesn't reach the password box + Keys.onPressed: { + if (event.key == Qt.Key_Left && !text) { + userList.decrementCurrentIndex(); + event.accepted = true + } + if (event.key == Qt.Key_Right && !text) { + userList.incrementCurrentIndex(); + event.accepted = true + } + } + + Connections { + target: root + onClearPassword: { + passwordBox.forceActiveFocus() + passwordBox.selectAll() + } + } + } + + Button { + id: loginButton + Accessible.name: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Unlock") + implicitHeight: passwordBox.height - units.smallSpacing * 0.5 // otherwise it comes out taller than the password field + text: ">" + Layout.leftMargin: 30 + + contentItem: Text { + text: loginButton.text + font: loginButton.font + opacity: enabled ? 1.0 : 0.3 + color: "#ffffff" + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + elide: Text.ElideRight + } + + background: Rectangle { + id: buttonBackground + width: 30 + height: 40 + radius: width / 2 + rotation: -90 + anchors.centerIn: parent + + gradient: Gradient { + GradientStop { position: 0.0; color: "#F9D423" } + GradientStop { position: 0.33; color: "#FF4E50" } + GradientStop { position: 1.0; color: "#8A2387" } + } + } + + onClicked: startLogin() + } + } +} diff --git a/kde/look-and-feel/contents/lockscreen/MediaControls.qml b/kde/look-and-feel/contents/lockscreen/MediaControls.qml new file mode 100644 index 0000000..d981153 --- /dev/null +++ b/kde/look-and-feel/contents/lockscreen/MediaControls.qml @@ -0,0 +1,162 @@ +/******************************************************************** + This file is part of the KDE project. + +Copyright (C) 2016 Kai Uwe Broulik + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*********************************************************************/ + +import QtQuick 2.5 +import QtQuick.Layouts 1.1 + +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 2.0 as PlasmaComponents +import org.kde.plasma.extras 2.0 as PlasmaExtras + +Item { + visible: mpris2Source.hasPlayer + implicitHeight: controlsRow.height + controlsRow.y + + RowLayout { + id: controlsRow + anchors.bottom: parent.bottom + y: units.smallSpacing // some distance to the password field + width: parent.width + height: units.gridUnit * 3 + spacing: 0 + + enabled: mpris2Source.canControl + + PlasmaCore.DataSource { + id: mpris2Source + + readonly property string source: "@multiplex" + readonly property var playerData: data[source] + + readonly property bool hasPlayer: sources.length > 1 && !!playerData + readonly property string identity: hasPlayer ? playerData.Identity : "" + readonly property bool playing: hasPlayer && playerData.PlaybackStatus === "Playing" + readonly property bool canControl: hasPlayer && playerData.CanControl + readonly property bool canGoBack: hasPlayer && playerData.CanGoPrevious + readonly property bool canGoNext: hasPlayer && playerData.CanGoNext + + readonly property var currentMetadata: hasPlayer ? playerData.Metadata : ({}) + + readonly property string track: { + var xesamTitle = currentMetadata["xesam:title"] + if (xesamTitle) { + return xesamTitle + } + // if no track title is given, print out the file name + var xesamUrl = currentMetadata["xesam:url"] ? currentMetadata["xesam:url"].toString() : "" + if (!xesamUrl) { + return "" + } + var lastSlashPos = xesamUrl.lastIndexOf('/') + if (lastSlashPos < 0) { + return "" + } + var lastUrlPart = xesamUrl.substring(lastSlashPos + 1) + return decodeURIComponent(lastUrlPart) + } + readonly property string artist: currentMetadata["xesam:artist"] || "" + readonly property string albumArt: currentMetadata["mpris:artUrl"] || "" + + engine: "mpris2" + connectedSources: [source] + + function startOperation(op) { + var service = serviceForSource(source) + var operation = service.operationDescription(op) + return service.startOperationCall(operation) + } + + function goPrevious() { + startOperation("Previous"); + } + function goNext() { + startOperation("Next"); + } + function playPause(source) { + startOperation("PlayPause"); + } + } + + Image { + id: albumArt + Layout.preferredWidth: height + Layout.fillHeight: true + asynchronous: true + fillMode: Image.PreserveAspectFit + source: mpris2Source.albumArt + sourceSize.height: height + visible: status === Image.Loading || status === Image.Ready + } + + Item { // spacer + width: units.smallSpacing + height: 1 + } + + ColumnLayout { + Layout.fillWidth: true + spacing: 0 + + PlasmaComponents.Label { + Layout.fillWidth: true + wrapMode: Text.NoWrap + elide: Text.ElideRight + text: mpris2Source.track || i18nd("plasma_lookandfeel_org.kde.lookandfeel", "No media playing") + textFormat: Text.PlainText + font.pointSize: theme.defaultFont.pointSize + 1 + maximumLineCount: 1 + } + + PlasmaExtras.DescriptiveLabel { + Layout.fillWidth: true + wrapMode: Text.NoWrap + elide: Text.ElideRight + // if no artist is given, show player name instead + text: mpris2Source.artist || mpris2Source.identity || "" + textFormat: Text.PlainText + font.pointSize: theme.smallestFont.pointSize + 1 + maximumLineCount: 1 + } + } + + PlasmaComponents.ToolButton { + enabled: mpris2Source.canGoBack + iconName: LayoutMirroring.enabled ? "media-skip-forward" : "media-skip-backward" + onClicked: mpris2Source.goPrevious() + visible: mpris2Source.canGoBack || mpris2Source.canGoNext + Accessible.name: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Previous track") + } + + PlasmaComponents.ToolButton { + Layout.fillHeight: true + Layout.preferredWidth: height // make this button bigger + iconName: mpris2Source.playing ? "media-playback-pause" : "media-playback-start" + onClicked: mpris2Source.playPause() + Accessible.name: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Play or Pause media") + } + + PlasmaComponents.ToolButton { + enabled: mpris2Source.canGoNext + iconName: LayoutMirroring.enabled ? "media-skip-backward" : "media-skip-forward" + onClicked: mpris2Source.goNext() + visible: mpris2Source.canGoBack || mpris2Source.canGoNext + Accessible.name: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Next track") + } + } +} diff --git a/kde/look-and-feel/contents/lockscreen/config.qml b/kde/look-and-feel/contents/lockscreen/config.qml new file mode 100644 index 0000000..921a038 --- /dev/null +++ b/kde/look-and-feel/contents/lockscreen/config.qml @@ -0,0 +1,44 @@ +import QtQuick 2.5 +import QtQuick.Controls 2.5 as QQC2 +import QtQuick.Layouts 1.1 + +ColumnLayout { + property alias cfg_alwaysShowClock: alwaysClock.checked + property alias cfg_showMediaControls: showMediaControls.checked + + spacing: 0 + + RowLayout { + spacing: units.largeSpacing / 2 + + QQC2.Label { + Layout.minimumWidth: formAlignment - units.largeSpacing //to match wallpaper config... + horizontalAlignment: Text.AlignRight + text: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Clock:") + } + QQC2.CheckBox { + id: alwaysClock + text: i18ndc("plasma_lookandfeel_org.kde.lookandfeel", "verb, to show something", "Always show") + } + Item { + Layout.fillWidth: true + } + } + + RowLayout { + spacing: units.largeSpacing / 2 + + QQC2.Label { + Layout.minimumWidth: formAlignment - units.largeSpacing //to match wallpaper config... + horizontalAlignment: Text.AlignRight + text: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Media controls:") + } + QQC2.CheckBox { + id: showMediaControls + text: i18ndc("plasma_lookandfeel_org.kde.lookandfeel", "verb, to show something", "Show") + } + Item { + Layout.fillWidth: true + } + } +} diff --git a/kde/look-and-feel/contents/lockscreen/config.xml b/kde/look-and-feel/contents/lockscreen/config.xml new file mode 100644 index 0000000..436a67e --- /dev/null +++ b/kde/look-and-feel/contents/lockscreen/config.xml @@ -0,0 +1,19 @@ + + + + + + + + true + + + + true + + + + diff --git a/kde/look-and-feel/contents/osd/Osd.qml b/kde/look-and-feel/contents/osd/Osd.qml new file mode 100644 index 0000000..2288ec1 --- /dev/null +++ b/kde/look-and-feel/contents/osd/Osd.qml @@ -0,0 +1,44 @@ +/* + * Copyright 2014 Martin Klapetek + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import QtQuick 2.0 +import QtQuick.Window 2.2 +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 2.0 as PlasmaComponents +import org.kde.plasma.extras 2.0 as PlasmaExtra + +PlasmaCore.Dialog { + id: root + location: PlasmaCore.Types.Floating + type: PlasmaCore.Dialog.OnScreenDisplay + outputOnly: true + + // OSD Timeout in msecs - how long it will stay on the screen + property int timeout: 1800 + // This is either a text or a number, if showingProgress is set to true, + // the number will be used as a value for the progress bar + property var osdValue + // Icon name to display + property string icon + // Set to true if the value is meant for progress bar, + // false for displaying the value as normal text + property bool showingProgress: false + + mainItem: OsdItem { + rootItem: root + } +} diff --git a/kde/look-and-feel/contents/osd/OsdItem.qml b/kde/look-and-feel/contents/osd/OsdItem.qml new file mode 100644 index 0000000..ea3c73a --- /dev/null +++ b/kde/look-and-feel/contents/osd/OsdItem.qml @@ -0,0 +1,87 @@ +/* + * Copyright 2014 Martin Klapetek + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import QtQuick 2.0 +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 2.0 as PlasmaComponents +import org.kde.plasma.extras 2.0 as PlasmaExtra +import QtQuick.Window 2.2 + +Item { + property QtObject rootItem + height: Math.min(units.gridUnit * 15, Screen.desktopAvailableHeight / 5) + width: height + + // /--------------------\ + // | spacing | + // | /----------------\ | + // | | | | + // | | icon | | + // | | | | + // | | | | + // | \----------------/ | + // | spacing | + // | [progressbar/text] | + // | spacing | + // \--------------------/ + + PlasmaCore.IconItem { + id: icon + + height: parent.height - Math.max(progressBar.height, label.height) + - ((units.smallSpacing/2) * 3) //it's an svg + width: parent.width + + source: rootItem.icon + } + + PlasmaComponents.ProgressBar { + id: progressBar + + anchors { + bottom: parent.bottom + left: parent.left + right: parent.right + margins: Math.floor(units.smallSpacing / 2) + } + + visible: rootItem.showingProgress + minimumValue: 0 + maximumValue: 100 + + value: Number(rootItem.osdValue) + } + PlasmaExtra.Heading { + id: label + anchors { + bottom: parent.bottom + left: parent.left + right: parent.right + margins: Math.floor(units.smallSpacing / 2) + } + + visible: !rootItem.showingProgress + text: rootItem.showingProgress ? "" : (rootItem.osdValue ? rootItem.osdValue : "") + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.WordWrap + maximumLineCount: 2 + elide: Text.ElideLeft + minimumPointSize: theme.defaultFont.pointSize + fontSizeMode: Text.HorizontalFit + textFormat: Text.PlainText + } +}