Implement Privacy Screen

* Add handles for window focus gained / focus lossed and connect to timer
* Clean up some of the PrivacyScreen.qml code
* Connect settings to PrivacyScreen visibility
This commit is contained in:
Joseph Donofry 2021-01-26 17:23:28 -05:00
parent cb93ac3402
commit bfeb766a91
No known key found for this signature in database
GPG Key ID: E8A1D78EF044B0CB
8 changed files with 137 additions and 35 deletions

View File

@ -22,6 +22,8 @@ if [ ! -z "$QMLFORMAT_PATH" ]; then
do
qmlformat -i "$f"
done;
else
echo "qmlformat not found; skipping qml formatting"
fi
git diff --exit-code

View File

@ -1,13 +1,28 @@
import QtGraphicalEffects 1.0
import QtQuick 2.12
import im.nheko 1.0
Item {
id: privacyScreen
property var timelineRoot
property var imageSource
property var imageSource: ""
property int screenTimeout
anchors.fill: parent
Connections {
target: TimelineManager
onFocusChanged: {
if (TimelineManager.isWindowFocused) {
screenSaverTimer.stop();
screenSaver.state = "Invisible";
} else {
screenSaverTimer.start();
}
}
}
Timer {
id: screenSaverTimer
@ -15,36 +30,98 @@ Item {
running: true
onTriggered: {
timelineRoot.grabToImage(function(result) {
screenSaver.state = "Visible";
imageSource = result.url;
screenSaver.visible = true;
particles.resume();
}, Qt.size(width, height));
}
}
// Reset screensaver timer when clicks are received
MouseArea {
anchors.fill: parent
// Pass mouse events through
propagateComposedEvents: true
hoverEnabled: true
onClicked: {
screenSaverTimer.restart();
mouse.accepted = false;
}
}
Rectangle {
id: screenSaver
state: "Invisible"
anchors.fill: parent
visible: false
color: "transparent"
states: [
State {
name: "Visible"
PropertyChanges {
target: screenSaver
visible: true
}
PropertyChanges {
target: screenSaver
opacity: 1
}
},
State {
name: "Invisible"
PropertyChanges {
target: screenSaver
opacity: 0
}
PropertyChanges {
target: screenSaver
visible: false
}
}
]
transitions: [
Transition {
from: "Visible"
to: "Invisible"
SequentialAnimation {
NumberAnimation {
target: screenSaver
property: "opacity"
duration: 250
easing.type: Easing.InQuad
}
NumberAnimation {
target: screenSaver
property: "visible"
duration: 0
}
}
},
Transition {
from: "Invisible"
to: "Visible"
SequentialAnimation {
NumberAnimation {
target: screenSaver
property: "visible"
duration: 0
}
NumberAnimation {
target: screenSaver
property: "opacity"
duration: 500
easing.type: Easing.InQuad
}
}
}
]
Image {
id: image
visible: screenSaver.visible
cache: false
anchors.fill: parent
source: imageSource
}
@ -65,17 +142,6 @@ Item {
radius: 50
}
MouseArea {
anchors.fill: parent
propagateComposedEvents: true
hoverEnabled: true
onClicked: {
screenSaver.visible = false;
screenSaverTimer.restart();
mouse.accepted = false;
}
}
}
}

View File

@ -312,6 +312,8 @@ ChatPage::ChatPage(QSharedPointer<UserSettings> userSettings, QWidget *parent)
&ChatPage::initializeMentions,
user_mentions_popup_,
&popups::UserMentions::initializeMentions);
connect(
this, &ChatPage::chatFocusChanged, view_manager_, &TimelineViewManager::chatFocusChanged);
connect(this, &ChatPage::syncUI, this, [this](const mtx::responses::Rooms &rooms) {
try {
room_list_->cleanupInvites(cache::invites());

View File

@ -127,7 +127,6 @@ public slots:
void receivedSessionKey(const std::string &room_id, const std::string &session_id);
void decryptDownloadedSecrets(mtx::secret_storage::AesHmacSha2KeyDescription keyDesc,
const SecretsToDecrypt &secrets);
signals:
void connectionLost();
void connectionRestored();
@ -176,6 +175,7 @@ signals:
void retrievedPresence(const QString &statusMsg, mtx::presence::PresenceState state);
void themeChanged();
void decryptSidebarChanged();
void chatFocusChanged(const bool focused);
//! Signals for device verificaiton
void receivedDeviceVerificationAccept(

View File

@ -130,6 +130,9 @@ MainWindow::MainWindow(QWidget *parent)
SLOT(iconActivated(QSystemTrayIcon::ActivationReason)));
connect(chat_page_, SIGNAL(contentLoaded()), this, SLOT(removeOverlayProgressBar()));
connect(this, &MainWindow::focusChanged, chat_page_, &ChatPage::chatFocusChanged);
connect(
chat_page_, &ChatPage::showUserSettingsPage, this, &MainWindow::showUserSettingsPage);
@ -204,6 +207,19 @@ MainWindow::resizeEvent(QResizeEvent *event)
QMainWindow::resizeEvent(event);
}
bool
MainWindow::event(QEvent *event)
{
auto type = event->type();
if (type == QEvent::WindowActivate) {
emit focusChanged(true);
} else if (type == QEvent::WindowDeactivate) {
emit focusChanged(false);
}
return QMainWindow::event(event);
}
void
MainWindow::adjustSideBars()
{

View File

@ -88,6 +88,7 @@ protected:
void closeEvent(QCloseEvent *event) override;
void resizeEvent(QResizeEvent *event) override;
void showEvent(QShowEvent *event) override;
bool event(QEvent *event) override;
private slots:
//! Show or hide the sidebars based on window's size.
@ -115,6 +116,9 @@ private slots:
virtual void setWindowTitle(int notificationCount);
signals:
void focusChanged(const bool focused);
private:
bool loadJdenticonPlugin();

View File

@ -836,13 +836,15 @@ UserSettingsPage::UserSettingsPage(QSharedPointer<UserSettings> settings, QWidge
decryptSidebar_,
tr("Decrypt the messages shown in the sidebar.\nOnly affects messages in "
"encrypted chats."));
boxWrap(tr("Encrypted chat privacy screen"),
boxWrap(tr("Privacy Screen"),
privacyScreen_,
tr("When the window loses focus, the timeline will\nbe blurred."));
boxWrap(tr("Privacy screen timeout"),
privacyScreenTimeout_,
tr("Set timeout for how long after window loses\nfocus before the screen"
" will be blurred.\nSet to 0 to blur immediately after focus loss."));
boxWrap(
tr("Privacy screen timeout"),
privacyScreenTimeout_,
tr("Set timeout (in seconds) for how long after window loses\nfocus before the screen"
" will be blurred.\nSet to 0 to blur immediately after focus loss. Max value of 1 "
"hour (3600 seconds)"));
boxWrap(tr("Show buttons in timeline"),
timelineButtonsToggle_,
tr("Show buttons to quickly reply, react or access additional options next to each "

View File

@ -36,6 +36,8 @@ class TimelineViewManager : public QObject
bool isInitialSync MEMBER isInitialSync_ READ isInitialSync NOTIFY initialSyncChanged)
Q_PROPERTY(
bool isNarrowView MEMBER isNarrowView_ READ isNarrowView NOTIFY narrowViewChanged)
Q_PROPERTY(
bool isWindowFocused MEMBER isWindowFocused_ READ isWindowFocused NOTIFY focusChanged)
public:
TimelineViewManager(CallManager *callManager, ChatPage *parent = nullptr);
@ -54,6 +56,7 @@ public:
Q_INVOKABLE TimelineModel *activeTimeline() const { return timeline_; }
Q_INVOKABLE bool isInitialSync() const { return isInitialSync_; }
bool isNarrowView() const { return isNarrowView_; }
bool isWindowFocused() const { return isWindowFocused_; }
Q_INVOKABLE void openImageOverlay(QString mxcUrl, QString eventId) const;
Q_INVOKABLE QColor userColor(QString id, QColor background);
Q_INVOKABLE QString escapeEmoji(QString str) const;
@ -83,11 +86,17 @@ signals:
void inviteUsers(QStringList users);
void showRoomList();
void narrowViewChanged();
void focusChanged();
public slots:
void updateReadReceipts(const QString &room_id, const std::vector<QString> &event_ids);
void receivedSessionKey(const std::string &room_id, const std::string &session_id);
void initWithMessages(const std::vector<QString> &roomIds);
void chatFocusChanged(bool focused)
{
isWindowFocused_ = focused;
emit focusChanged();
}
void setHistoryView(const QString &room_id);
TimelineModel *getHistoryView(const QString &room_id)
@ -145,8 +154,9 @@ private:
TimelineModel *timeline_ = nullptr;
CallManager *callManager_ = nullptr;
bool isInitialSync_ = true;
bool isNarrowView_ = false;
bool isInitialSync_ = true;
bool isNarrowView_ = false;
bool isWindowFocused_ = false;
QHash<QString, QColor> userColors;