aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--filter.cpp4
-rw-r--r--filter.h1
-rw-r--r--main.cpp2
-rw-r--r--main.qml39
-rw-r--r--pages/settings/Settings.qml13
-rw-r--r--pages/settings/SettingsLayout.qml84
6 files changed, 135 insertions, 8 deletions
diff --git a/filter.cpp b/filter.cpp
index 3ba011bf..9129d92b 100644
--- a/filter.cpp
+++ b/filter.cpp
@@ -38,6 +38,10 @@ filter::filter(QObject *parent) :
}
bool filter::eventFilter(QObject *obj, QEvent *ev) {
+ if(ev->type() == QEvent::KeyPress || ev->type() == QEvent::MouseButtonRelease){
+ emit userActivity();
+ }
+
switch(ev->type()) {
case QEvent::KeyPress: {
QKeyEvent *ke = static_cast<QKeyEvent*>(ev);
diff --git a/filter.h b/filter.h
index 4c998a29..bb3a78b7 100644
--- a/filter.h
+++ b/filter.h
@@ -48,6 +48,7 @@ signals:
void sequenceReleased(const QVariant &o, const QVariant &seq);
void mousePressed(const QVariant &o, const QVariant &x, const QVariant &y);
void mouseReleased(const QVariant &o, const QVariant &x, const QVariant &y);
+ void userActivity();
};
#endif // FILTER_H
diff --git a/main.cpp b/main.cpp
index 5ebaff50..82229c23 100644
--- a/main.cpp
+++ b/main.cpp
@@ -324,6 +324,6 @@ int main(int argc, char *argv[])
QObject::connect(eventFilter, SIGNAL(sequenceReleased(QVariant,QVariant)), rootObject, SLOT(sequenceReleased(QVariant,QVariant)));
QObject::connect(eventFilter, SIGNAL(mousePressed(QVariant,QVariant,QVariant)), rootObject, SLOT(mousePressed(QVariant,QVariant,QVariant)));
QObject::connect(eventFilter, SIGNAL(mouseReleased(QVariant,QVariant,QVariant)), rootObject, SLOT(mouseReleased(QVariant,QVariant,QVariant)));
-
+ QObject::connect(eventFilter, SIGNAL(userActivity()), rootObject, SLOT(userActivity()));
return app.exec();
}
diff --git a/main.qml b/main.qml
index 84f7d38d..d8f9a699 100644
--- a/main.qml
+++ b/main.qml
@@ -75,6 +75,7 @@ ApplicationWindow {
property var cameraUi
property bool remoteNodeConnected: false
property bool androidCloseTapped: false;
+ property int userLastActive; // epoch
// Default daemon addresses
readonly property string localDaemonAddress : persistentSettings.nettype == NetworkType.MAINNET ? "localhost:18081" : persistentSettings.nettype == NetworkType.TESTNET ? "localhost:28081" : "localhost:38081"
property string currentDaemonAddress;
@@ -219,6 +220,8 @@ ApplicationWindow {
// Local daemon settings
walletManager.setDaemonAddress(localDaemonAddress)
+ // enable user inactivity timer
+ userInActivityTimer.running = true;
// wallet already opened with wizard, we just need to initialize it
if (typeof wizard.m_wallet !== 'undefined') {
@@ -932,6 +935,8 @@ ApplicationWindow {
rootItem.state = "wizard"
// reset balance
leftPanel.balanceText = leftPanel.unlockedBalanceText = walletManager.displayAmount(0);
+ // disable inactivity timer
+ userInActivityTimer.running = false;
}
function hideMenu() {
@@ -1041,6 +1046,8 @@ ApplicationWindow {
property int segregationHeight: 0
property int kdfRounds: 1
property bool hideBalance: false
+ property bool lockOnUserInActivity: true
+ property int lockOnUserInActivityInterval: 10 // minutes
}
// Information dialog
@@ -1696,6 +1703,12 @@ ApplicationWindow {
triggeredOnStart: false
}
+ Timer {
+ id: userInActivityTimer
+ interval: 2000; running: false; repeat: true
+ onTriggered: checkInUserActivity()
+ }
+
Rectangle {
id: statusMessage
z: 99
@@ -1823,6 +1836,32 @@ ApplicationWindow {
leftPanel.balanceLabelText = qsTr("Balance")
}
+ function userActivity() {
+ // register user activity
+ var epoch = Math.floor((new Date).getTime()/1000);
+ appWindow.userLastActive = epoch;
+ }
+
+ function checkInUserActivity() {
+ if(!persistentSettings.lockOnUserInActivity) return;
+
+ // prompt password after X seconds of inactivity
+ var epoch = Math.floor((new Date).getTime() / 1000);
+ var inactivity = epoch - appWindow.userLastActive;
+ if(inactivity < (persistentSettings.lockOnUserInActivityInterval * 60)) return;
+
+ passwordDialog.onAcceptedCallback = function() {
+ if(walletPassword === passwordDialog.password){
+ passwordDialog.close();
+ } else {
+ passwordDialog.showError(qsTr("Wrong password"));
+ }
+ }
+
+ passwordDialog.onRejectedCallback = function() { appWindow.showWizard(); }
+ passwordDialog.open();
+ }
+
// Daemon console
DaemonConsole {
id: daemonConsolePopup
diff --git a/pages/settings/Settings.qml b/pages/settings/Settings.qml
index 5aabcccd..9aa44461 100644
--- a/pages/settings/Settings.qml
+++ b/pages/settings/Settings.qml
@@ -65,17 +65,16 @@ ColumnLayout {
onCurrentViewChanged: {
if (previousView) {
-// if (typeof previousView.onPageClosed === "function") {
-// previousView.onPageClosed();
-// }
+ if (typeof previousView.onPageClosed === "function") {
+ previousView.onPageClosed();
+ }
}
previousView = currentView
if (currentView) {
stackView.replace(currentView)
- // Component.onCompleted is called before wallet is initilized
-// if (typeof currentView.onPageCompleted === "function") {
-// currentView.onPageCompleted();
-// }
+ if (typeof currentView.onPageCompleted === "function") {
+ currentView.onPageCompleted();
+ }
}
}
diff --git a/pages/settings/SettingsLayout.qml b/pages/settings/SettingsLayout.qml
index 974da5e3..6914a438 100644
--- a/pages/settings/SettingsLayout.qml
+++ b/pages/settings/SettingsLayout.qml
@@ -40,6 +40,14 @@ Rectangle {
height: 1400
Layout.fillWidth: true
+ function onPageCompleted() {
+ userInactivitySliderTimer.running = true;
+ }
+
+ function onPageClosed() {
+ userInactivitySliderTimer.running = false;
+ }
+
ColumnLayout {
id: settingsUI
property int itemHeight: 60 * scaleRatio
@@ -70,6 +78,82 @@ Rectangle {
text: qsTr("Hide balance") + translationManager.emptyString
}
+ MoneroComponents.CheckBox {
+ visible: !isMobile
+ id: userInActivityCheckbox
+ checked: persistentSettings.lockOnUserInActivity
+ onClicked: persistentSettings.lockOnUserInActivity = !persistentSettings.lockOnUserInActivity
+ text: qsTr("Lock wallet on inactivity") + translationManager.emptyString
+ }
+
+ ColumnLayout {
+ visible: userInActivityCheckbox.checked
+ Layout.fillWidth: true
+ Layout.topMargin: 6 * scaleRatio
+ Layout.leftMargin: 42 * scaleRatio
+ spacing: 0
+
+ MoneroComponents.TextBlock {
+ font.pixelSize: 14 * scaleRatio
+ Layout.fillWidth: true
+ text: {
+ var val = userInactivitySlider.value;
+ var minutes = val > 1 ? qsTr("minutes") : qsTr("minute");
+
+ qsTr("After ") + val + " " + minutes + translationManager.emptyString;
+ }
+ }
+
+ Slider {
+ id: userInactivitySlider
+ from: 1
+ value: persistentSettings.lockOnUserInActivityInterval
+ to: 60
+ leftPadding: 0
+ stepSize: 1
+ snapMode: Slider.SnapAlways
+
+ background: Rectangle {
+ x: parent.leftPadding
+ y: parent.topPadding + parent.availableHeight / 2 - height / 2
+ implicitWidth: 200 * scaleRatio
+ implicitHeight: 4 * scaleRatio
+ width: parent.availableWidth
+ height: implicitHeight
+ radius: 2
+ color: MoneroComponents.Style.grey
+
+ Rectangle {
+ width: parent.visualPosition * parent.width
+ height: parent.height
+ color: MoneroComponents.Style.green
+ radius: 2
+ }
+ }
+
+ handle: Rectangle {
+ x: parent.leftPadding + parent.visualPosition * (parent.availableWidth - width)
+ y: parent.topPadding + parent.availableHeight / 2 - height / 2
+ implicitWidth: 18 * scaleRatio
+ implicitHeight: 18 * scaleRatio
+ radius: 8
+ color: parent.pressed ? "#f0f0f0" : "#f6f6f6"
+ border.color: MoneroComponents.Style.grey
+ }
+ }
+
+ Timer {
+ // @TODO: Slider.onMoved{} is available in Qt > 5.9, use a hacky timer for now
+ id: userInactivitySliderTimer
+ interval: 1000; running: false; repeat: true
+ onTriggered: {
+ if(persistentSettings.lockOnUserInActivityInterval != userInactivitySlider.value) {
+ persistentSettings.lockOnUserInActivityInterval = userInactivitySlider.value;
+ }
+ }
+ }
+ }
+
MoneroComponents.TextBlock {
visible: isMobile
font.pixelSize: 14