Commit 46022538 authored by Devin Lin's avatar Devin Lin 🎨
Browse files

Implement lockscreen mockups

parent da3d3c02
/*
Copyright (C) 2019 Nicolas Fella <nicolas.fella@gmx.de>
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 <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.8
import QtQuick.Layouts 1.1
import QtQuick.Controls 2.5
import QtGraphicalEffects 1.12
import org.kde.plasma.core 2.0
ColumnLayout {
readonly property bool softwareRendering: GraphicsInfo.api === GraphicsInfo.Software
property int alignment
Layout.alignment: alignment
spacing: units.gridUnit
Label {
text: Qt.formatTime(timeSource.data["Local"]["DateTime"])
text: Qt.formatTime(timeSource.data["Local"]["DateTime"], "h:mm ap")
color: ColorScope.textColor
style: softwareRendering ? Text.Outline : Text.Normal
styleColor: softwareRendering ? ColorScope.backgroundColor : "transparent" //no outline, doesn't matter
font.pointSize: 40
Layout.alignment: Qt.AlignHCenter
styleColor: softwareRendering ? ColorScope.backgroundColor : "transparent" // no outline, doesn't matter
Layout.alignment: alignment
font.weight: Font.Light // this font weight may switch to regular on distros that don't have a light variant
font.pointSize: 36
layer.enabled: true
layer.effect: DropShadow {
verticalOffset: 1
radius: 4
samples: 6
color: "#757575"
}
}
Label {
text: Qt.formatDate(timeSource.data["Local"]["DateTime"], Qt.DefaultLocaleLongDate)
text: Qt.formatDate(timeSource.data["Local"]["DateTime"], "ddd, MMM d")
color: ColorScope.textColor
style: softwareRendering ? Text.Outline : Text.Normal
styleColor: softwareRendering ? ColorScope.backgroundColor : "transparent" //no outline, doesn't matter
font.pointSize: 16
Layout.alignment: Qt.AlignHCenter
styleColor: softwareRendering ? ColorScope.backgroundColor : "transparent" // no outline, doesn't matter
Layout.alignment: alignment
font.pointSize: 10
layer.enabled: true
layer.effect: DropShadow {
verticalOffset: 1
radius: 4
samples: 6
color: "#757575"
}
}
DataSource {
id: timeSource
......
/*
* Copyright 2019 Marco Martin <mart@kde.org>
*
* 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) version 3 or any later version
* accepted by the membership of KDE e.V. (or its successor approved
* by the membership of KDE e.V.), which shall act as a proxy
* defined in Section 14 of version 3 of the license.
*
* 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 <http://www.gnu.org/licenses/>
*/
import QtQuick 2.10
import org.kde.kirigami 2.11 as Kirigami
MouseArea {
id: delegate
property Item contentItem
property bool draggable: false
signal dismissRequested
anchors.fill: contentItem
implicitWidth: contentItem ? contentItem.implicitWidth : 0
implicitHeight: contentItem ? contentItem.implicitHeight : 0
opacity: 1 - Math.min(1, 1.5 * Math.abs(x) / width)
drag {
axis: Drag.XAxis
target: draggable && Kirigami.Settings.tabletMode ? this : null
}
onReleased: {
if (Math.abs(x) > width / 2) {
delegate.dismissRequested();
} else {
slideAnim.restart();
}
}
NumberAnimation {
id: slideAnim
target: delegate
property: "x"
to: 0
duration: units.longDuration
}
}
/*
Copyright (C) 2020 Devin Lin <espidev@gmail.com>
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 <http://www.gnu.org/licenses/>.
*/
import QtQuick 2.12
import QtQuick.Controls 1.1
import QtQuick.Layouts 1.1
import QtGraphicalEffects 1.12
import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.workspace.keyboardlayout 1.0
Rectangle {
color: Qt.rgba(250, 250, 250, 0.85) // slightly translucent background, for key contrast
property string pinLabel: qsTr("Enter PIN")
// for displaying temporary number in pin dot display
property string lastKeyPressValue: "0"
property int indexWithNumber: -2
// keypad functions
function backspace() {
lastKeyPressValue = "0";
indexWithNumber = -2;
root.password = root.password.substr(0, root.password.length - 1);
}
function enter() {
authenticator.tryUnlock(root.password);
}
function keyPress(data) {
if (keypad.pinLabel !== qsTr("Enter PIN")) {
keypad.pinLabel = qsTr("Enter PIN");
}
lastKeyPressValue = data;
indexWithNumber = root.password.length;
root.password += data
// trigger turning letter into dot later
letterTimer.restart();
}
Connections {
target: authenticator
function onFailed() {
root.password = "";
pinLabel = qsTr("Wrong PIN")
}
}
// listen for keyboard events
Keys.onPressed: {
if (event.modifiers === Qt.NoModifier) {
if (event.key === Qt.Key_Backspace) {
backspace();
} else if (event.key === Qt.Key_Return) {
enter();
} else if (event.text != "") {
keyPress(event.text);
}
}
}
// trigger turning letter into dot after 500 milliseconds
Timer {
id: letterTimer
interval: 500
running: false
repeat: false
onTriggered: {
lastKeyPressValue = 0;
indexWithNumber = -2;
}
}
ColumnLayout {
anchors {
left: parent.left
right: parent.right
top: parent.top
bottom: parent.bottom
topMargin: units.gridUnit
bottomMargin: units.gridUnit
}
spacing: units.gridUnit
// pin dot display
Item {
Layout.alignment: Qt.AlignHCenter
Layout.minimumHeight: units.gridUnit * 0.5
Layout.maximumWidth: parent.width
Label {
visible: root.password.length === 0
anchors.centerIn: parent
text: pinLabel
font.pointSize: 12
color: "#616161"
}
RowLayout {
id: dotDisplay
anchors.centerIn: parent
height: units.gridUnit // maintain height when letter is shown
spacing: 6
Repeater {
model: root.password.length
delegate: Rectangle { // dot
visible: index !== indexWithNumber // hide dot if number is shown
Layout.preferredWidth: units.gridUnit * 0.25
Layout.preferredHeight: Layout.preferredWidth
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
radius: width
color: "#424242"
}
}
Label { // number/letter
visible: root.password.length-1 === indexWithNumber // hide label if no label needed
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
color: "#424242"
text: lastKeyPressValue
font.pointSize: 10
}
}
}
// separator
Rectangle {
Layout.fillWidth: true
height: 1
color: "#eeeeee"
}
// number keys
GridLayout {
property string thePw
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
Layout.leftMargin: units.gridUnit * 0.5
Layout.rightMargin: units.gridUnit * 0.5
Layout.maximumWidth: units.gridUnit * 22
Layout.maximumHeight: units.gridUnit * 12.5
columns: 4
// numpad keys
Repeater {
model: ["1", "2", "3", "R", "4", "5", "6", "0", "7", "8", "9", "E"]
delegate: Item {
Layout.fillWidth: true
Layout.fillHeight: true
Rectangle {
id: keyRect
anchors.centerIn: parent
width: parent.width
height: parent.height
radius: 5
color: "white"
visible: modelData.length > 0
MouseArea {
anchors.fill: parent
onPressed: parent.color = "#e0e0e0"
onReleased: parent.color = "white"
onClicked: {
if (modelData === "R") {
backspace();
} else if (modelData === "E") {
enter();
} else {
keyPress(modelData);
}
}
}
}
DropShadow {
anchors.fill: keyRect
source: keyRect
cached: true
horizontalOffset: 0
verticalOffset: 1
radius: 4
samples: 6
color: "#e0e0e0"
}
PlasmaComponents.Label {
visible: modelData !== "R" && modelData !== "E"
text: modelData
anchors.centerIn: parent
font.pointSize: 18
color: "#424242"
}
PlasmaCore.IconItem {
visible: modelData === "R"
anchors.centerIn: parent
// colorGroup: PlasmaCore.ColorScope.backgroundColor
source: "edit-clear"
}
PlasmaCore.IconItem {
visible: modelData === "E"
anchors.centerIn: parent
// colorGroup: PlasmaCore.ColorScope.backgroundColor
source: "go-next"
}
}
}
}
}
}
......@@ -22,68 +22,183 @@ import QtGraphicalEffects 1.12
import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.workspace.keyboardlayout 1.0
import org.kde.notificationmanager 1.1 as Notifications
import "../components"
PlasmaCore.ColorScope {
id: root
property string password
property bool isWidescreen: root.height < root.width * 0.75
property bool notificationsShown: phoneNotificationsList.count !== 0
colorGroup: PlasmaCore.Theme.ComplementaryColorGroup
anchors.fill: parent
BrightnessContrast {
id: darken
function isPinDrawerOpen() {
return passwordFlickable.contentY === passwordFlickable.columnHeight;
}
// blur background once keypad is open
FastBlur {
id: blur
cached: true
anchors.fill: parent
source: wallpaper
brightness: -(passwordFlickable.contentY / passwordFlickable.columnHeight * 0.6)
}
DropShadow {
id: clockShadow
anchors.fill: clock
source: clock
horizontalOffset: 1
verticalOffset: 1
radius: 6
samples: 14
spread: 0.3
color: PlasmaCore.ColorScope.backgroundColor
visible: true
// hide when keypad is shown
property bool doBlur: notificationsShown || isPinDrawerOpen() // only blur once animation finished for performance
Behavior on doBlur {
NumberAnimation {
target: blur
property: "radius"
duration: 1000
to: blur.doBlur ? 0 : 50
easing.type: Easing.InOutQuad
}
PropertyAction {
target: blur
property: "visible"
value: blur.doBlur
}
}
}
Notifications.WatchedNotificationsModel {
id: notifModel
}
// header bar
SimpleHeaderBar {
anchors {
top: parent.top
left: parent.left
right: parent.right
}
height: units.gridUnit
opacity: 1 - (passwordFlickable.contentY / passwordFlickable.columnHeight)
}
Clock {
id: clock
property Item shadow: clockShadow
anchors.leftMargin: units.gridUnit
anchors.rightMargin: units.gridUnit
anchors.topMargin: units.gridUnit * 3
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
// phone clock component
ColumnLayout {
id: phoneClockComponent
visible: !isWidescreen
anchors {
top: parent.top
topMargin: root.height / 2 - (height / 2 + units.gridUnit * 2)
left: parent.left
right: parent.right
}
spacing: 0
opacity: 1 - (passwordFlickable.contentY / passwordFlickable.columnHeight)
states: State {
name: "notification"; when: notificationsShown
PropertyChanges { target: phoneClockComponent; anchors.topMargin: units.gridUnit * 5 }
}
transitions: Transition {
NumberAnimation {
properties: "anchors.topMargin"
easing.type: Easing.InOutQuad
}
}
Clock {
id: phoneClock
alignment: Qt.AlignHCenter
Layout.bottomMargin: units.gridUnit * 2 // keep spacing even if media controls are gone
}
MediaControls {
Layout.alignment: Qt.AlignHCenter
Layout.fillWidth: true
Layout.maximumWidth: units.gridUnit * 25
Layout.minimumWidth: units.gridUnit * 15
Layout.leftMargin: units.gridUnit
Layout.rightMargin: units.gridUnit
z: 5
}
}
MediaControls {
// tablet clock component
Item {
id: tabletClockComponent
visible: isWidescreen
width: parent.width / 2
anchors {
top: parent.top
bottom: parent.bottom
left: parent.left
leftMargin: units.gridUnit * 3
}
ColumnLayout {
id: tabletLayout
anchors.centerIn: parent
spacing: units.gridUnit
opacity: 1 - (passwordFlickable.contentY / passwordFlickable.columnHeight)
Clock {
id: tabletClock
alignment: Qt.AlignLeft
Layout.fillWidth: true
Layout.minimumWidth: units.gridUnit * 20
}
MediaControls {
Layout.alignment: Qt.AlignLeft
Layout.fillWidth: true
Layout.maximumWidth: units.gridUnit * 25
Layout.minimumWidth: units.gridUnit * 20
z: 5
}
}
}
// phone notifications list
NotificationsList {
id: phoneNotificationsList
visible: !isWidescreen
z: passwordFlickable.contentY === 0 ? 5 : 0 // prevent mousearea from interfering with pin drawer
anchors {
top: phoneClockComponent.bottom
topMargin: units.gridUnit
bottom: scrollUpIcon.top
bottomMargin: units.gridUnit
left: parent.left
leftMargin: units.gridUnit
right: parent.right
rightMargin: units.gridUnit
verticalCenter: parent.verticalCenter
}
opacity: 1 - (passwordFlickable.contentY / passwordFlickable.columnHeight)
z: 5
}
// tablet notifications list
ColumnLayout {
visible: isWidescreen
z: passwordFlickable.contentY === 0 ? 5 : 0 // prevent mousearea from interfering with pin drawer
anchors {
top: parent.top
bottom: parent.bottom
left: tabletClockComponent.right
right: parent.right
rightMargin: units.gridUnit
}
NotificationsList {
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
Layout.fillWidth: true
Layout.minimumHeight: this.notificationListHeight
Layout.minimumWidth: units.gridUnit * 15
Layout.maximumWidth: units.gridUnit * 25
}
}
// scroll up icon
PlasmaCore.IconItem {
id: scrollUpIcon
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.bottomMargin: units.gridUnit + passwordFlickable.contentY * 0.5
anchors.horizontalCenter: parent.horizontalCenter
opacity: 1 - (passwordFlickable.contentY / passwordFlickable.columnHeight)
......@@ -116,8 +231,10 @@ PlasmaCore.ColorScope {
// wipe password if it is more than half way down the screen
onContentYChanged: {
if (contentY < columnHeight / 2)
if (contentY < columnHeight / 2) {
root.password = "";
keypad.pinLabel = qsTr("Enter PIN");
}
}
ColumnLayout {
......@@ -125,99 +242,22 @@ PlasmaCore.ColorScope {
anchors.bottom: parent.bottom
width: parent.width
spacing: units.gridUnit * 2
spacing: units.gridUnit
opacity: Math.sin((Math.PI / 2) * (passwordFlickable.contentY / passwordFlickable.columnHeight) + 1.5 * Math.PI) + 1
PlasmaComponents.Label {
// scroll down icon