Skip to content

Commit

Permalink
feat(LoginPage): perform network checks before Login/Sync
Browse files Browse the repository at this point in the history
- expose the `checking` property from the C++ backend, fix it in order
not to start when `!active`
- display an additional popup when net checks enabled and we are not
online
  • Loading branch information
caybro committed Dec 12, 2024
1 parent 57c9240 commit cf9b44d
Show file tree
Hide file tree
Showing 6 changed files with 178 additions and 28 deletions.
1 change: 1 addition & 0 deletions storybook/pages/OnboardingLayoutPage.qml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ SplitView {
id: onboarding
SplitView.fillWidth: true
SplitView.fillHeight: true
networkChecksEnabled: true
onboardingStore: OnboardingStore {
readonly property int keycardState: ctrlKeycardState.currentValue // enum Onboarding.KeycardState
property int keycardRemainingPinAttempts: 5
Expand Down
1 change: 1 addition & 0 deletions storybook/qmlTests/tests/tst_OnboardingLayout.qml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ Item {

OnboardingLayout {
anchors.fill: parent
networkChecksEnabled: false
onboardingStore: OnboardingStore {
readonly property int keycardState: mockDriver.keycardState // enum Onboarding.KeycardState
property int keycardRemainingPinAttempts: 5
Expand Down
36 changes: 23 additions & 13 deletions ui/StatusQ/include/StatusQ/networkchecker.h
Original file line number Diff line number Diff line change
@@ -1,41 +1,51 @@
#pragma once

#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QObject>
#include <QQmlParserStatus>
#include <QTimer>

#include <chrono>

using namespace std::chrono_literals;
class QNetworkAccessManager;

/// Checks if the internet connection is available, when active.
/// It checks the connection every 30 seconds as long as the \c active property is \c true.
class NetworkChecker : public QObject
/// It checks the connection every 30 seconds as long as the \c active property is \c true (by default it is)
class NetworkChecker : public QObject, public QQmlParserStatus
{
Q_OBJECT
Q_PROPERTY(bool isOnline READ isOnline NOTIFY isOnlineChanged)
Q_PROPERTY(bool active READ isActive WRITE setActive NOTIFY activeChanged)
Q_INTERFACES(QQmlParserStatus)

Q_PROPERTY(bool isOnline READ isOnline NOTIFY isOnlineChanged FINAL)
Q_PROPERTY(bool active READ isActive WRITE setActive NOTIFY activeChanged FINAL)
Q_PROPERTY(bool checking READ checking NOTIFY checkingChanged FINAL)

public:
explicit NetworkChecker(QObject* parent = nullptr);
explicit NetworkChecker(QObject *parent = nullptr);
bool isOnline() const;

bool isActive() const;
void setActive(bool active);

Q_INVOKABLE void checkNetwork();

protected:
void classBegin() override;
void componentComplete() override;

signals:
void isOnlineChanged(bool online);
void activeChanged(bool active);
void checkingChanged();

private:
QNetworkAccessManager manager;
QTimer timer;
bool online = false;
bool active = true;
constexpr static std::chrono::milliseconds checkInterval = 30s;

void checkNetwork();
void onFinished(QNetworkReply* reply);
void onFinished(QNetworkReply *reply);
void updateRegularCheck(bool active);
};

bool m_checking{false};
bool checking() const;
void setChecking(bool checking);
};
55 changes: 41 additions & 14 deletions ui/StatusQ/src/networkchecker.cpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
#include "StatusQ/networkchecker.h"

NetworkChecker::NetworkChecker(QObject* parent)
namespace {
using namespace std::chrono_literals;

constexpr static auto checkInterval = 30s;
}

NetworkChecker::NetworkChecker(QObject *parent)
: QObject(parent)
{
manager.setTransferTimeout();
connect(&manager, &QNetworkAccessManager::finished, this, &NetworkChecker::onFinished);
connect(&timer, &QTimer::timeout, this, &NetworkChecker::checkNetwork);

updateRegularCheck(active);
}

bool NetworkChecker::isOnline() const
Expand All @@ -18,16 +23,26 @@ void NetworkChecker::checkNetwork()
{
QNetworkRequest request(QUrl(QStringLiteral("http://fedoraproject.org/static/hotspot.txt")));
manager.get(request);
setChecking(true);
}

void NetworkChecker::classBegin()
{
// empty on purpose
}

void NetworkChecker::componentComplete() {
updateRegularCheck(active);
}

void NetworkChecker::onFinished(QNetworkReply* reply)
void NetworkChecker::onFinished(QNetworkReply *reply)
{
bool wasOnline = online;
setChecking(false);
const auto wasOnline = online;
online = (reply->error() == QNetworkReply::NoError);
reply->deleteLater();

if(wasOnline != online)
{
if (wasOnline != online) {
emit isOnlineChanged(online);
}
}
Expand All @@ -39,7 +54,8 @@ bool NetworkChecker::isActive() const

void NetworkChecker::setActive(bool active)
{
if(active == this->active) return;
if (active == this->active)
return;

this->active = active;
emit activeChanged(active);
Expand All @@ -49,13 +65,24 @@ void NetworkChecker::setActive(bool active)

void NetworkChecker::updateRegularCheck(bool active)
{
if(active)
{
if (active) {
checkNetwork();
timer.start(checkInterval);
}
else
{
} else {
timer.stop();
}
}
}

bool NetworkChecker::checking() const
{
return m_checking;
}

void NetworkChecker::setChecking(bool checking)
{
if (m_checking == checking)
return;

m_checking = checking;
emit checkingChanged();
}
1 change: 1 addition & 0 deletions ui/app/AppLayouts/Onboarding2/OnboardingLayout.qml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Page {

property int splashScreenDurationMs: 30000
property bool biometricsAvailable: Qt.platform.os === Constants.mac
required property bool networkChecksEnabled

readonly property alias stack: stack
readonly property alias primaryFlow: d.primaryFlow // Onboarding.PrimaryFlow enum
Expand Down
112 changes: 111 additions & 1 deletion ui/app/AppLayouts/Onboarding2/pages/LoginPage.qml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
import QtQml.Models 2.15

import StatusQ 0.1
import StatusQ.Core 0.1
import StatusQ.Components 0.1
import StatusQ.Controls 0.1
Expand All @@ -17,6 +18,8 @@ import utils 1.0
OnboardingPage {
id: root

required property bool networkChecksEnabled

title: qsTr("Log in")

signal loginWithSeedphraseRequested()
Expand Down Expand Up @@ -119,6 +122,11 @@ OnboardingPage {
}
}

NetworkChecker {
id: netChecker
active: root.networkChecksEnabled
}

Component {
id: loginWithSyncAck
StatusDialog {
Expand All @@ -127,6 +135,7 @@ OnboardingPage {
width: 480
padding: 20
destroyOnClose: true
onOpened: if (root.networkChecksEnabled) netChecker.checkNetwork()
contentItem: ColumnLayout {
spacing: 20
StatusBaseText {
Expand Down Expand Up @@ -169,12 +178,113 @@ OnboardingPage {
text: qsTr("Continue")
enabled: ack1.checked && ack2.checked && ack3.checked
onClicked: {
root.loginWithSyncingRequested()
if (root.networkChecksEnabled && !netChecker.isOnline) {
networkCheckPopup.createObject(root, {netChecker}).open()
} else {
root.loginWithSyncingRequested()
}
close()
}
}
}
}
}
}



Component {
id: networkCheckPopup
StatusDialog {
objectName: "networkCheckPopup"
title: qsTr("Status does not have access to local network")
width: 480
padding: 20
destroyOnClose: true

required property var netChecker

contentItem: ColumnLayout {
spacing: 20
StatusBaseText {
Layout.fillWidth: true
wrapMode: Text.Wrap
text: qsTr("Status must be connected to the local network on this device for you to be able to log in via syncing. To rectify this...")
}
OnboardingFrame {
Layout.fillWidth: true
dropShadow: false
cornerRadius: Theme.radius
horizontalPadding: 20
verticalPadding: 12
contentItem: ColumnLayout {
spacing: 12
StatusBaseText {
Layout.fillWidth: true
wrapMode: Text.Wrap
color: Theme.palette.baseColor1
text: qsTr("1. Open System Settings")
}
StatusBaseText {
Layout.fillWidth: true
wrapMode: Text.Wrap
color: Theme.palette.baseColor1
text: qsTr("2. Click Privacy & Security")
}
StatusBaseText {
Layout.fillWidth: true
wrapMode: Text.Wrap
color: Theme.palette.baseColor1
text: qsTr("3. Click Local Network")
}
StatusBaseText {
Layout.fillWidth: true
wrapMode: Text.Wrap
color: Theme.palette.baseColor1
text: qsTr("4. Find Status")
}
StatusBaseText {
Layout.fillWidth: true
wrapMode: Text.Wrap
color: Theme.palette.baseColor1
text: qsTr("5. Toggle the switch to grant access")
}
StatusBaseText {
Layout.fillWidth: true
wrapMode: Text.Wrap
color: Theme.palette.baseColor1
text: qsTr("6. Click %1 below").arg(`<font color="${Theme.palette.directColor1}">` +
qsTr("Verify local network access") +
"</font>")
}
}
}
}
footer: StatusDialogFooter {
spacing: Theme.padding
rightButtons: ObjectModel {
StatusFlatButton {
text: qsTr("Cancel")
onClicked: close()
}
StatusButton {
objectName: "btnVerifyNet"
text: loading ? qsTr("Verifying") : qsTr("Verify local network access")
loading: netChecker.checking
interactive: !loading
onClicked: netChecker.checkNetwork()
}
}
}
Connections {
target: netChecker
function onIsOnlineChanged() {
if (netChecker.isOnline) {
root.loginWithSyncingRequested()
close()
}
}
}
}
}
}

0 comments on commit cf9b44d

Please sign in to comment.