Commit 4622bc51 authored by Aleksi Suomalainen's avatar Aleksi Suomalainen Committed by GitHub

Merge pull request #69 from eekkelund/master

[DeviceLock] Fix #67 and add beautiful sliding gesture to codepad
parents 3eb6ebd9 6ebe08f1
...@@ -27,6 +27,7 @@ BuildRequires: pkgconfig(Qt5Core) ...@@ -27,6 +27,7 @@ BuildRequires: pkgconfig(Qt5Core)
BuildRequires: pkgconfig(Qt5Quick) BuildRequires: pkgconfig(Qt5Quick)
BuildRequires: pkgconfig(lipstick-qt5) >= 0.12.0 BuildRequires: pkgconfig(lipstick-qt5) >= 0.12.0
BuildRequires: pkgconfig(Qt5Compositor) BuildRequires: pkgconfig(Qt5Compositor)
BuildRequires: pkgconfig(nemodevicelock)
Provides: lipstick-colorful-home-qt5 Provides: lipstick-colorful-home-qt5
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include "glacierwindowmodel.h" #include "glacierwindowmodel.h"
#include <QScreen> #include <QScreen>
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
HomeApplication app(argc, argv, QString()); HomeApplication app(argc, argv, QString());
......
...@@ -6,6 +6,7 @@ import QtQuick.Layouts 1.0 ...@@ -6,6 +6,7 @@ import QtQuick.Layouts 1.0
import org.nemomobile.lipstick 0.1 import org.nemomobile.lipstick 0.1
import org.nemomobile.devicelock 1.0 import org.nemomobile.devicelock 1.0
import org.nemomobile.dbus 1.0
import "scripts/desktop.js" as Desktop import "scripts/desktop.js" as Desktop
...@@ -13,49 +14,12 @@ Item { ...@@ -13,49 +14,12 @@ Item {
id: root id: root
property bool shouldAuthenticate: Lipstick.compositor.visible property bool shouldAuthenticate: Lipstick.compositor.visible
&& authenticator.availableMethods !== 0
property int remainingAttempts property int remainingAttempts
property AuthenticationInput authenticationInput
onShouldAuthenticateChanged: {
if (shouldAuthenticate) {
DeviceLock.authorization.requestChallenge()
} else {
authenticator.cancel()
DeviceLock.authorization.relinquishChallenge()
}
}
Component.onCompleted: {
DeviceLock.authorization.requestChallenge()
}
Connections {
target: DeviceLock.authorization
onChallengeIssued: {
authenticator.authenticate(
DeviceLock.authorization.challengeCode,
DeviceLock.authorization.allowedMethods)
}
}
Authenticator {
id: authenticator
onAuthenticated: {
DeviceLock.unlock(authenticationToken)
Desktop.instance.setLockScreen(false)
Desktop.instance.codepadVisible = false
remainingAttempts = 0
}
onFeedback: {
console.log('### still locked', feedback, attemptsRemaining)
remainingAttempts = attemptsRemaining
animation.start()
}
}
ColumnLayout { ColumnLayout {
anchors.fill: parent anchors.fill: parent
spacing: Theme.itemSpacingExtraSmall spacing: Theme.itemSpacingLarge
SequentialAnimation { SequentialAnimation {
id: animation; id: animation;
...@@ -66,14 +30,23 @@ Item { ...@@ -66,14 +30,23 @@ Item {
} }
NumberAnimation { target: codePad; property: "anchors.horizontalCenterOffset"; to: 0; duration: 100 } NumberAnimation { target: codePad; property: "anchors.horizontalCenterOffset"; to: 0; duration: 100 }
} }
Row {
anchors.horizontalCenter: parent.horizontalCenter
width: parent.width
Label { Label {
id: feedbackLabel
font.pixelSize: Theme.fontSizeMedium font.pixelSize: Theme.fontSizeMedium
width: parent.width text: " "
text: remainingAttempts > 0 ? qsTr("Attempts remaining:") + " " + remainingAttempts : "" }
anchors.horizontalCenter: parent.horizontalCenter Label {
id: attemptsRemainingLabel
font.pixelSize: Theme.fontSizeMedium
text: " "
}
} }
TextField { TextField {
id: lockCodeField id: lockCodeField
anchors.topMargin: Theme.itemSpacingMedium
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
readOnly: true readOnly: true
echoMode: TextInput.PasswordEchoOnEdit echoMode: TextInput.PasswordEchoOnEdit
...@@ -91,18 +64,28 @@ Item { ...@@ -91,18 +64,28 @@ Item {
delegate: delegate:
Button { Button {
id:button id:button
opacity: 1
Layout.maximumWidth: Theme.itemWidthSmall Layout.maximumWidth: Theme.itemWidthSmall
Layout.maximumHeight: Theme.itemHeightHuge * 2 Layout.maximumHeight: Theme.itemHeightHuge * 2
Layout.minimumHeight: Theme.itemHeightHuge * 1.5 Layout.minimumHeight: Theme.itemHeightHuge * 1.5
Text {
id: numLabel
text: modelData text: modelData
font.pixelSize: Theme.fontSizeLarge
anchors.centerIn: parent
color: "white"
}
onClicked: { onClicked: {
if (button.text !== "Ca" && button.text !== "OK") { displayOffTimer.restart()
lockCodeField.insert(lockCodeField.cursorPosition, button.text) feedbackLabel.text = " "
attemptsRemainingLabel.text = " "
if (numLabel.text !== "Ca" && numLabel.text !== "OK") {
lockCodeField.insert(lockCodeField.cursorPosition, numLabel.text)
} else { } else {
if (button.text === "OK") { if (numLabel.text === "OK") {
authenticator.enterLockCode(lockCodeField.text) authenticationInput.enterSecurityCode(lockCodeField.text)
lockCodeField.text = "" lockCodeField.text = ""
} else if (button.text === "Ca"){ } else if (numLabel.text === "Ca"){
lockCodeField.text = "" lockCodeField.text = ""
} }
} }
...@@ -111,4 +94,35 @@ Item { ...@@ -111,4 +94,35 @@ Item {
} }
} }
} }
function displayFeedback(feedback, data) {
switch(feedback) {
case AuthenticationInput.EnterSecurityCode:
feedbackLabel.text = qsTr("Enter security code")
break
case AuthenticationInput.IncorrectSecurityCode:
feedbackLabel.text = qsTr("Incorrect code")
if(authenticationInput.maximumAttempts !== -1) {
attemptsRemainingLabel.text = qsTr("("+(authenticationInput.maximumAttempts-data.attemptsRemaining)+
"/"+authenticationInput.maximumAttempts+")")
}
animation.start()
break
case AuthenticationInput.TemporarilyLocked:
feedbackLabel.text = qsTr("Temporarily locked")
}
}
function displayError(error) {
console.log("displayError "+error)
}
Connections {
target: root.authenticationInput
onFeedback: root.displayFeedback(feedback, data)
onError: root.displayError(error)
}
} }
...@@ -27,15 +27,139 @@ Image { ...@@ -27,15 +27,139 @@ Image {
} }
} }
// Swipes on the lockscreen
MouseArea { MouseArea {
id:mouseArea id:mouseArea
property bool gestureStarted: false
property string gesture: ""
property int startX
property int threshold: Theme.itemHeightHuge * 2
property int swipeDistance
property string action: ""
anchors.fill: parent anchors.fill: parent
onPressed: {
startX = mouseX;
}
onMouseXChanged: {
// Checks which was it left or right swipe
if(mouseX > (startX+threshold)) {
gesture = "right"
gestureStarted = true;
}
else if(mouseX < (startX+threshold)) {
gesture = "left"
gestureStarted = true;
}
// Makes codepad follow the swipe
if(codePad.inView) {
if(gesture == "right") {
swipeDistance = mouseX - startX
codePad.x = swipeDistance
}
if(gesture == "left") {
swipeDistance = startX - mouseX
codePad.x = -swipeDistance
}
}else {
if(gesture == "right") {
swipeDistance = mouseX - startX
codePad.x = swipeDistance - parent.width
}
else if(gesture == "left") {
swipeDistance = startX - mouseX
codePad.x = parent.width - swipeDistance
}
}
}
// Animation to snap codepad into view or out of view
onReleased: {
displayOffTimer.restart()
if(codePad.inView) {
if(gesture == "right") {
if(swipeDistance > threshold) {
startCodePadAnimation(parent.width)
codePad.inView = false
}else {
startCodePadAnimation(0)
codePad.inView = true
}
}else if(gesture == "left") {
if(swipeDistance > threshold) {
startCodePadAnimation(-parent.width)
codePad.inView = false
}else {
startCodePadAnimation(0)
codePad.inView = true
}
}
}else {
if(swipeDistance > threshold) {
startCodePadAnimation(0)
codePad.inView = true
}else {
if(gesture == "right") {
startCodePadAnimation(-parent.width)
codePad.inView = false
}
else {
startCodePadAnimation(parent.width)
codePad.inView = false
}
}
}
gestureStarted = false
}
function startCodePadAnimation(value) {
snapCodePadAnimation.valueTo = value
snapCodePadAnimation.start()
}
}
SequentialAnimation {
id: snapCodePadAnimation
property alias valueTo: codePadAnimation.to
NumberAnimation {
id: codePadAnimation
target: codePad
property: "x"
duration: 200
easing.type: Easing.OutQuint
}
}
SequentialAnimation {
id: unlockAnimation
property alias valueTo: unlockNumAnimation.to
property alias setProperty: unlockNumAnimation.property
NumberAnimation {
id: unlockNumAnimation
target: lockScreen
property: "y"
to: -height
duration: 250
easing.type: Easing.OutQuint
}
onStopped: {
setLockScreen(false)
}
} }
Connections { Connections {
target:Lipstick.compositor target:Lipstick.compositor
onDisplayOff: { onDisplayOff: {
displayOn = false displayOn = false
displayOffTimer.stop() displayOffTimer.stop()
codePad.x = -parent.width
codePad.inView = false
} }
onDisplayOn:{ onDisplayOn:{
displayOn = true displayOn = true
...@@ -66,7 +190,65 @@ Image { ...@@ -66,7 +190,65 @@ Image {
} }
} }
} }
DeviceLockUI {
id: codePad
property bool inView: false
property bool gestureStarted: mouseArea.gestureStarted
x: width * 2
visible: DeviceLock.state == DeviceLock.Locked && lockscreenVisible()
width: lockScreen.width
height: lockScreen.height / 2
opacity: (1-Math.abs((1 - (-1)) * (x - (-parent.width)) / (parent.width - (-parent.width)) + (-1)))
authenticationInput: DeviceLockAuthenticationInput {
readonly property bool unlocking: registered
&& DeviceLock.state >= DeviceLock.Locked && DeviceLock.state < DeviceLock.Undefined
registered: lockscreenVisible()
active: lockscreenVisible()
onUnlockingChanged: {
if (unlocking) {
DeviceLock.unlock()
} else {
DeviceLock.cancel()
}
}
onAuthenticationEnded: {
if(confirmed) {
unlockAnimationHelper(mouseArea.gesture)
}else {
}
}
function unlockAnimationHelper(gesture) {
if(gesture == "left") {
unlockAnimation.setProperty = "x"
unlockAnimation.valueTo = -width
unlockAnimation.start()
}
if(gesture == "right") {
unlockAnimation.setProperty = "x"
unlockAnimation.valueTo = width
unlockAnimation.start()
}
}
}
anchors {
verticalCenter: lockScreen.verticalCenter
}
onGestureStartedChanged: {
if(gestureStarted) {
mouseArea.z = 2
}else {
mouseArea.z = 0
}
}
}
ListView { ListView {
id: notificationColumn id: notificationColumn
opacity: codePad.visible ? 1 - codePad.opacity : 1 opacity: codePad.visible ? 1 - codePad.opacity : 1
......
...@@ -66,9 +66,9 @@ Page { ...@@ -66,9 +66,9 @@ Page {
id: desktop id: desktop
property alias lockscreen: lockScreen property alias lockscreen: lockScreen
property alias switcher: switcher property alias switcher: switcher
property alias codepad: codePad
property int statusBarHeight: statusbar.height property int statusBarHeight: statusbar.height
property bool codepadVisible: false property bool codepadVisible: false
property bool deviceLocked: DeviceLock.state >= DeviceLock.Locked
// Implements back key navigation // Implements back key navigation
...@@ -80,7 +80,6 @@ Page { ...@@ -80,7 +80,6 @@ Page {
} else { Qt.quit(); } } else { Qt.quit(); }
} }
} }
Statusbar { Statusbar {
id: statusbar id: statusbar
enabled: DeviceLock.state !== DeviceLock.Locked enabled: DeviceLock.state !== DeviceLock.Locked
...@@ -165,7 +164,7 @@ Page { ...@@ -165,7 +164,7 @@ Page {
} }
Lockscreen { Lockscreen {
id: lockScreen id: lockScreen
visible: lockscreenVisible()//DeviceLock.state == DeviceLock.Locked visible: lockscreenVisible()
width: parent.width width: parent.width
height: parent.height height: parent.height
z: 200 z: 200
......
...@@ -114,7 +114,6 @@ Compositor { ...@@ -114,7 +114,6 @@ Compositor {
id: overlayLayer id: overlayLayer
z: 5 z: 5
//visible: root.appActive
} }
Item { Item {
...@@ -137,7 +136,7 @@ Compositor { ...@@ -137,7 +136,7 @@ Compositor {
property real lockThreshold: 0.25 property real lockThreshold: 0.25
property int lockscreenX property int lockscreenX
property int lockscreenY property int lockscreenY
enabled: true//!Desktop.instance.codepadVisible//DeviceLock.state != DeviceLock.Locked enabled: DeviceLock.state != DeviceLock.Locked
onGestureStarted: { onGestureStarted: {
swipeAnimation.stop() swipeAnimation.stop()
...@@ -148,13 +147,7 @@ Compositor { ...@@ -148,13 +147,7 @@ Compositor {
state = "swipe" state = "swipe"
} }
else if (!root.appActive && DeviceLock.state !== DeviceLock.Locked) { else if (!root.appActive && DeviceLock.state !== DeviceLock.Locked) {
state = "lock" state = "cover"
}
else if (Desktop.instance.lockscreenVisible() && DeviceLock.state === DeviceLock.Locked && !Desktop.instance.codepadVisible) {
state = "pullCodepad"
}
else if (Desktop.instance.lockscreenVisible() && DeviceLock.state === DeviceLock.Locked && Desktop.instance.codepadVisible) {
state = "pushCodepad"
} }
} }
...@@ -183,14 +176,6 @@ Compositor { ...@@ -183,14 +176,6 @@ Compositor {
setDisplayOff() setDisplayOff()
} }
} }
// Brings up codepad, only left and right swipes allowed for it for now
else if (Desktop.instance.lockscreenVisible() && !Desktop.instance.codepad.visible && DeviceLock.state == DeviceLock.Locked && (gesture !== "down" && gesture !== "up")) {
Desktop.instance.codepadVisible = true
}
// Hides codepad but does not unlock the code, only left and right swipes allowed for now
else if (Desktop.instance.lockscreenVisible() && Desktop.instance.codepad.visible && DeviceLock.state == DeviceLock.Locked && gesture !== "down" && gesture !== "up") {
Desktop.instance.codepadVisible = false
}
// Unlocks if no security code required // Unlocks if no security code required
else if (DeviceLock.state !== DeviceLock.Locked && Desktop.instance.lockscreenVisible()) { else if (DeviceLock.state !== DeviceLock.Locked && Desktop.instance.lockscreenVisible()) {
Desktop.instance.setLockScreen(false) Desktop.instance.setLockScreen(false)
...@@ -218,9 +203,9 @@ Compositor { ...@@ -218,9 +203,9 @@ Compositor {
y: gestureArea.horizontal ? 0 : gestureArea.value y: gestureArea.horizontal ? 0 : gestureArea.value
} }
}, },
// Lock state is for when screen is locked but no security code required, can be swiped from any edge // Cover state is for when screen is covered but no security code required, can be swiped from any edge
State { State {
name: "lock" name: "cover"
when: Desktop.instance.lockscreenVisible() when: Desktop.instance.lockscreenVisible()
PropertyChanges { PropertyChanges {
target: Desktop.instance.lockscreen target: Desktop.instance.lockscreen
...@@ -249,65 +234,7 @@ Compositor { ...@@ -249,65 +234,7 @@ Compositor {
Desktop.instance.lockscreen.height : Desktop.instance.lockscreen.height :
Desktop.instance.lockscreen.width)+gestureArea.value) ) ) Desktop.instance.lockscreen.width)+gestureArea.value) ) )
} }
},
// pullCodepad is when you are pulling codepad into view to enter security code
State {
name: "pullCodepad"
when: Desktop.instance.codepadVisible
PropertyChanges {
target: Desktop.instance
codepadVisible: true
} }
PropertyChanges {
target: gestureArea
delayReset: true
}
PropertyChanges {
target: Desktop.instance.codepad
// Confusing logic and math to get the codepad follow your finger
x: gestureArea.lockscreenX + (gestureArea.value < 0 ? Desktop.instance.lockscreen.width : -Desktop.instance.lockscreen.width) +
((gestureArea.horizontal) ? (Desktop.instance.lockscreenVisible()?(gestureArea.value) :
(gestureArea.gesture == "right" ?
((Desktop.instance.lockscreen.width === topmostWindow.width) ?
-Desktop.instance.lockscreen.width :
-Desktop.instance.lockscreen.height)+Math.abs(gestureArea.value) :
((Desktop.instance.lockscreen.width === topmostWindow.width) ?
Desktop.instance.lockscreen.width :
Desktop.instance.lockscreen.height)+gestureArea.value) ) : 0 )
// Bringing up the codepad opacity from 0 to 1
opacity: gestureArea.horizontal ? (gestureArea.value < 0 ? (gestureArea.value / -Desktop.instance.lockscreen.width) :
gestureArea.value / Desktop.instance.lockscreen.width) : 0
}
},
// pushCodepad is when you are pushing the codepad away without entering a security code
State {
name: "pushCodepad"
when: Desktop.instance.lockscreenVisible() && DeviceLock.state === DeviceLock.Locked && Desktop.instance.codepadVisible
PropertyChanges {
target: gestureArea
delayReset: true
}
PropertyChanges {
target: Desktop.instance.codepad
// Confusing logic for the codepad to follow your swipe
x: gestureArea.lockscreenX +
((gestureArea.horizontal) ? (Desktop.instance.lockscreenVisible()?(gestureArea.value) :
(gestureArea.gesture == "right" ?
((Desktop.instance.lockscreen.width === topmostWindow.width) ?
-Desktop.instance.lockscreen.width :
-Desktop.instance.lockscreen.height)+Math.abs(gestureArea.value) :
((Desktop.instance.lockscreen.width === topmostWindow.width) ?
Desktop.instance.lockscreen.width :
Desktop.instance.lockscreen.height)+gestureArea.value) ) : 0 )
// Hiding the codepad with opacity fading from 1 to 0
opacity: 1 - (gestureArea.horizontal ? (gestureArea.value < 0 ? (gestureArea.value / -Desktop.instance.lockscreen.width) :
gestureArea.value / Desktop.instance.lockscreen.width) : 0)
}
}
] ]
SequentialAnimation { SequentialAnimation {
......
...@@ -100,14 +100,15 @@ QT += quick compositor ...@@ -100,14 +100,15 @@ QT += quick compositor
DEFINES += QT_COMPOSITOR_QUICK DEFINES += QT_COMPOSITOR_QUICK
HEADERS += \ HEADERS += \
glacierwindowmodel.h glacierwindowmodel.h
QT += dbus
LIBS += -lnemodevicelock
MOC_DIR = .moc MOC_DIR = .moc
SOURCES += \ SOURCES += \
main.cpp \ main.cpp \
glacierwindowmodel.cpp glacierwindowmodel.cpp
PKGCONFIG += lipstick-qt5 \
PKGCONFIG += lipstick-qt5 nemodevicelock
OTHER_FILES += qml/*.qml \ OTHER_FILES += qml/*.qml \
qml/MainScreen.qml \ qml/MainScreen.qml \
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment