Index: sources/gui/qml/globals/Variables.qml =================================================================== diff -u -re5a802bc26647388cfea4f1d46ae22570ec2dba3 -rea52cee2614f319804690a9b1d5091bed9676753 --- sources/gui/qml/globals/Variables.qml (.../Variables.qml) (revision e5a802bc26647388cfea4f1d46ae22570ec2dba3) +++ sources/gui/qml/globals/Variables.qml (.../Variables.qml) (revision ea52cee2614f319804690a9b1d5091bed9676753) @@ -130,6 +130,9 @@ readonly property int settingsWIFIMargin : settingsBLEMargin readonly property int settingsWIFIInputWidth : 225 readonly property int settingsWIFISpacing : 20 + readonly property int settingsWIFINetworkHeight : 85 + readonly property int settingsWIFINetworkWidth : 375 + readonly property int settingsWIFINetworksWidth : settingsWIFINetworkWidth + 50 readonly property int rinsebackIconDiameterDefault : 85 readonly property int rinsebackIconDiameterResumePause : 110 Index: sources/gui/qml/pages/SettingsWifi.qml =================================================================== diff -u -re5a802bc26647388cfea4f1d46ae22570ec2dba3 -rea52cee2614f319804690a9b1d5091bed9676753 --- sources/gui/qml/pages/SettingsWifi.qml (.../SettingsWifi.qml) (revision e5a802bc26647388cfea4f1d46ae22570ec2dba3) +++ sources/gui/qml/pages/SettingsWifi.qml (.../SettingsWifi.qml) (revision ea52cee2614f319804690a9b1d5091bed9676753) @@ -15,6 +15,7 @@ // Qt import QtQuick 2.12 +import QtQuick.Controls 2.12 // for scrollbar // Project import Gui.Actions 0.1; @@ -41,50 +42,36 @@ regExp:/^(([01]?[0-9]?[0-9]|2([0-4][0-9]|5[0-5]))\.){3}([01]?[0-9]?[0-9]|2([0-4][0-9]|5[0-5]))$/ } - Rectangle { id: _rect - height: parent.height - (Variables.settingsWIFIMargin + 2*Variables.mainMenuHeight) - width: parent.width - Variables.settingsWIFIMargin - - color: Colors.transparent + TitleText { id: _title + anchors.horizontalCenter: parent.horizontalCenter anchors { top: parent.top - topMargin: Variables.settingsWIFIMargin left: parent.left - leftMargin: Variables.settingsWIFIMargin + topMargin: Variables.settingsWIFIMargin } + text: qsTr("Wifi Settings") + } - TitleText { id: _title - anchors.horizontalCenter: _rect.horizontalCenter - anchors.top: _rect.top - anchors.left: _rect.left - text: qsTr("Wifi Settings") + Rectangle { id: _rect + color: Colors.transparent + anchors { + top: _title.bottom + left: parent.left + leftMargin: Variables.settingsWIFIMargin + right: parent.right + rightMargin: Variables.settingsWIFIMargin + bottom: parent.bottom + bottomMargin: 2*Variables.mainMenuHeight } - Rectangle { id: _status - anchors { - top: _title.bottom - left: parent.left - } - - color: "transparent" - height: Variables.settingsWIFIButtonHeight - width: Variables.settingsWIFIButtonWidth - Text { id: _status_text - text: qsTr("Status: ") - color: Colors.textMain - font.pixelSize: Fonts.fontPixelTextRectExtra - wrapMode: Text.WordWrap - width: parent.width - } - } - TextEntry { id: _ip_address textInput.width: Variables.settingsWIFIInputWidth line.width: Variables.settingsWIFIInputWidth label.width: Variables.settingsWIFIInputWidth anchors { - top: _status.bottom + top: parent.top + topMargin: Variables.settingsWIFIMargin left: parent.left } validator: ipValidator @@ -149,13 +136,74 @@ left: _rect.left } - backgroundColor: Colors.backgroundButtonSelect + backgroundColor: vNetworkModel.scanInProgress ? Colors.backgroundButtonNormal : Colors.backgroundButtonSelect + textColor: vNetworkModel.scanInProgress ? "grey" : Colors.textMain height: Variables.settingsWIFIButtonHeight width: Variables.settingsWIFIButtonWidth text.text: qsTr("Scan") - animated: true - onClicked: vNetworkModel.doScan() + onClicked: { + if (!vNetworkModel.scanInProgress) + vNetworkModel.doScan() + } } - } + NotificationBarSmall { id: _notification + imageAutoSize: true + height : 25 + color: "transparent" + imageSource : "" + text : "STATUS PLACEHOLDER" + textColor: Colors.textMain + textfontSize: Fonts.fontPixelTextRectExtra + } + + ListView { id: _pairedDevices + model: vNetworkModel + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.right: parent.right + width: Variables.settingsWIFINetworksWidth + clip: true + spacing: 10 + + ScrollBar.vertical: ScrollBar { id: _scrollBarPairedDevices + anchors.right: parent.right + anchors.rightMargin: 3 + contentItem: Rectangle { + color: Colors.backgroundRangeRect + implicitWidth: 6 + radius: width / 2 + width: 3 + } + } + + delegate: TouchRect { + id: _network + anchors.right: parent.right + anchors.rightMargin: Variables.settingsWIFISpacing + height: Variables.settingsWIFINetworkHeight + width: Variables.settingsWIFINetworkWidth + color: Colors.backgroundMain + border.color: Colors.borderButton + border.width: 4 + radius: 20 + animated: true + + Text { + id: _ssid + anchors { + centerIn: parent + } + font.pixelSize: Fonts.fontPixelTextRectExtra + text: ssid + color: Colors.textMain + } + + onClicked: { + console.debug("Clicked " + ssid); + } + } + } + + } } Index: sources/storage/StorageGlobals.cpp =================================================================== diff -u -re5a802bc26647388cfea4f1d46ae22570ec2dba3 -rea52cee2614f319804690a9b1d5091bed9676753 --- sources/storage/StorageGlobals.cpp (.../StorageGlobals.cpp) (revision e5a802bc26647388cfea4f1d46ae22570ec2dba3) +++ sources/storage/StorageGlobals.cpp (.../StorageGlobals.cpp) (revision ea52cee2614f319804690a9b1d5091bed9676753) @@ -52,7 +52,7 @@ #elif BUILD_FOR_TARGET const char *Wifi_Scripts_Dir = "/home/root/"; #endif - const char *Wifi_Scripts_Scan_For_Networks = "scanForNetworks.sh"; + const char *Wifi_Scripts_Scan_For_Networks = "scanForNetworks.sh"; const char *SDCard_Base_Path_Name = "/media/sd-card/"; } Index: sources/view/VNetworkModel.cpp =================================================================== diff -u -re5a802bc26647388cfea4f1d46ae22570ec2dba3 -rea52cee2614f319804690a9b1d5091bed9676753 --- sources/view/VNetworkModel.cpp (.../VNetworkModel.cpp) (revision e5a802bc26647388cfea4f1d46ae22570ec2dba3) +++ sources/view/VNetworkModel.cpp (.../VNetworkModel.cpp) (revision ea52cee2614f319804690a9b1d5091bed9676753) @@ -4,6 +4,7 @@ // Project #include "VNetworkModel.h" #include "WifiInterface.h" +#include "Logger.h" using namespace View; @@ -13,19 +14,26 @@ */ void VNetworkModel::initConnections() { - connect(this, SIGNAL(didScan()), + connect(this, SIGNAL(didScan()), &_WifiInterface, SLOT(doScan())); + + connect(&_WifiInterface, SIGNAL(didAddNetwork(const Network)), + this, SLOT(doAddNetwork(const Network))); + + connect(&_WifiInterface, SIGNAL(didScanStatusChanged(const bool)), + this, SLOT(onScanStatusChanged(const bool))); } /*! * \brief VNetworkModel::addNetwork * Adds a network to the network model * \param network (Network) - the network to add to the model */ -void VNetworkModel::addNetwork(const Network &network) +void VNetworkModel::addNetwork(const Network &vNetwork) { + LOG_DEBUG(QString("Adding network with SSID: %1").arg(vNetwork.ssid())); beginInsertRows(QModelIndex(), rowCount(), rowCount()); - _networks << network; + _networks << vNetwork; endInsertRows(); } @@ -71,7 +79,7 @@ QHash VNetworkModel::roleNames() const { QHash roles; roles[SSIDRole] = "ssid"; - roles[SecurityLevelRole] = "security_level"; + roles[SecurityLevelRole] = "securityLevel"; roles[StatusRole] = "status"; return roles; } @@ -83,3 +91,32 @@ void VNetworkModel::doScan() { emit didScan(); } + +/*! + * \brief VNetworkModel::onAddNetwork + * Slot that receives a request to add a new network + * \param vNetwork - (Network) the new network to add + */ +void VNetworkModel::doAddNetwork(const Network &vNetwork) +{ + if (!_networks.contains(vNetwork)) + { + qDebug() << QString("Adding network with SSID: %1.").arg(vNetwork.ssid()); + LOG_DEBUG(QString("Adding network with SSID: %1.").arg(vNetwork.ssid())); + addNetwork(vNetwork); + } + else + { + LOG_DEBUG(QString("Skipping adding network with SSID: %1. It already exists").arg(vNetwork.ssid())); + } +} + +/*! + * \brief VNetworkModel::onScanStatusChanged + * Called when the scan status changes. Updates QML with the current state + * \param vScanning - (bool) true if scanning, false otherwise + */ +void VNetworkModel::onScanStatusChanged(const bool &vScanning) +{ + scanInProgress(vScanning); +} Index: sources/view/VNetworkModel.h =================================================================== diff -u -re5a802bc26647388cfea4f1d46ae22570ec2dba3 -rea52cee2614f319804690a9b1d5091bed9676753 --- sources/view/VNetworkModel.h (.../VNetworkModel.h) (revision e5a802bc26647388cfea4f1d46ae22570ec2dba3) +++ sources/view/VNetworkModel.h (.../VNetworkModel.h) (revision ea52cee2614f319804690a9b1d5091bed9676753) @@ -5,6 +5,7 @@ #include // Project +#include "main.h" #include "VView.h" #include "Network.h" @@ -25,6 +26,8 @@ { Q_OBJECT + PROPERTY(bool, scanInProgress, false) + public: // Note: VIEW_DEC_CLASS(VNetworkModel) requires QObject as the parent, so it's necessary to define it here // Otherwise a VIEW_DEC_CLASS macro could allow specifying the parent class with QObject as the default @@ -44,11 +47,17 @@ public slots: void doScan(); + void doAddNetwork(const Network &vNetwork); protected: QHash roleNames() const; private: - QList _networks; void initConnections(); + + QList _networks; + +private slots: + void onScanStatusChanged(const bool &vScanning); + }; } Index: sources/wifi/Network.h =================================================================== diff -u -re5a802bc26647388cfea4f1d46ae22570ec2dba3 -rea52cee2614f319804690a9b1d5091bed9676753 --- sources/wifi/Network.h (.../Network.h) (revision e5a802bc26647388cfea4f1d46ae22570ec2dba3) +++ sources/wifi/Network.h (.../Network.h) (revision ea52cee2614f319804690a9b1d5091bed9676753) @@ -22,12 +22,12 @@ WPA_TKIP, WPA_TKIP_AES, WPA_AES, - WPA2_AES, + WPA2_AES_PERSONAL, + WPA2_AES_ENTERPRISE }; enum SIGNAL_LEVEL { - REFRESHING, NO_SIGNAL, LVL_1, LVL_2, @@ -43,27 +43,86 @@ DISCONNECTING }; + bool operator==(const Network &d1) { + if (ssid() == d1.ssid()) + return true; + return false; + } + + bool operator>(const Network &d1) { + if (signalLevel() > d1.signalLevel()) + return true; + return false; + } + + bool operator<(const Network &d1) { + if (signalLevel() < d1.signalLevel()) + return true; + return false; + } + QString ssid() const { return _ssid; } + void ssid(const QString &vSSID) { + _ssid = vSSID; + } SECURITY_LEVEL security() const { return _security; } + void security(const SECURITY_LEVEL &vSecurity) { + _security = vSecurity; + } + SIGNAL_LEVEL signalLevel() const { + return _signalLevel; + } + void signalLevel(const SIGNAL_LEVEL &vLevel) { + _signalLevel = vLevel; + } STATUS status() const { return _status; } + void status(const STATUS &vStatus) { + _status = vStatus; + } + QString macAddress() const { + return _macAddress; + } + void macAddress(const QString &vMacAddress) { + _macAddress = vMacAddress; + } - explicit Network(); - explicit Network(const int vSSID) {_ssid = vSSID; } - explicit Network(const int vSSID, const SECURITY_LEVEL vSecurityLevel, const STATUS vStatus) { + SIGNAL_LEVEL convertSignalLevel(int vLevel) { + if (vLevel == 0) + return NO_SIGNAL; + else if (vLevel >= -50) + return LVL_5; + else if (vLevel >= -60) + return LVL_4; + else if (vLevel >= -70) + return LVL_3; + else if (vLevel >= -80) + return LVL_2; + else if (vLevel >= -90) + return LVL_1; + + return NO_SIGNAL; + } + + explicit Network(const QString &vMacAddress) {_macAddress = vMacAddress; } + explicit Network(const QString &vMacAddress, const QString &vSSID, const SECURITY_LEVEL &vSecurityLevel, const STATUS &vStatus, const int &vSignalLevel) { + _macAddress = vMacAddress; _ssid = vSSID; _security = vSecurityLevel; _status = vStatus; + _signalLevel = convertSignalLevel(vSignalLevel); } private: - QString _ssid = ""; + QString _macAddress; + QString _ssid; SECURITY_LEVEL _security = UNSUPPORTED; + SIGNAL_LEVEL _signalLevel = NO_SIGNAL; STATUS _status = NOT_CONNECTED; }; Index: sources/wifi/WifiInterface.cpp =================================================================== diff -u -re5a802bc26647388cfea4f1d46ae22570ec2dba3 -rea52cee2614f319804690a9b1d5091bed9676753 --- sources/wifi/WifiInterface.cpp (.../WifiInterface.cpp) (revision e5a802bc26647388cfea4f1d46ae22570ec2dba3) +++ sources/wifi/WifiInterface.cpp (.../WifiInterface.cpp) (revision ea52cee2614f319804690a9b1d5091bed9676753) @@ -80,17 +80,17 @@ */ void WifiInterface::doScan() { - // if scan is already running, return + if (_scanRunning) { LOG_DEBUG("Wifi network scan is already running."); return; } - // otherwise, start the detached process + LOG_DEBUG("Scanning for Wifi Access Points..."); _scanProcess.setWorkingDirectory(Wifi_Scripts_Dir); _scanRunning = true; - // TODO: emit scan running to view so scan button is disabled + emit didScanStatusChanged(_scanRunning); _scanProcess.start(Wifi_Scripts_Scan_For_Networks); } @@ -109,5 +109,50 @@ LOG_DEBUG(out); LOG_DEBUG(err); _scanRunning = false; - // TODO: emit scan finished to view so scan button is re-enabled. + emit didScanStatusChanged(_scanRunning); + onParseWifiScan(out); } + +/*! + * \brief Network::onParseWifiScan + * Extract desired information from the wifi scan output. Sorts by signal stength + * + * \param output - (QString) output collected from QProcess execution + */ +void WifiInterface::onParseWifiScan(const QString &output) +{ + QList networks; + QStringList temp = output.split("Cell"); + const QString signalLevelSearchTerm = "Signal level="; + const QString macAddressSearchTerm = "Address:"; + const QString ssidSearchTerm = "ESSID:"; + const QString groupCipherSearchTerm = "Group Cipher"; + const QString authSuitesSearchTerm = "Authentication Suites"; + + for (const QString &line : temp) + { + if (line.contains(ssidSearchTerm) && line.contains(macAddressSearchTerm) && line.contains(signalLevelSearchTerm)) + { + QString ssid = line.split(ssidSearchTerm)[1].split("\n")[0].replace("\"", "").trimmed(); + if (ssid == "") + continue; + QString macAddress = line.split(macAddressSearchTerm)[1].split("\n")[0].trimmed(); + int signalLevel = line.split(signalLevelSearchTerm)[1].split("dBm")[0].trimmed().toInt(); + + bool isCCMP = line.split(groupCipherSearchTerm)[1].split("\n")[0].contains("CCMP"); + bool isEnterprise = line.split(authSuitesSearchTerm)[1].split("\n")[0].contains("802.1x"); + bool isPersonal = line.split(authSuitesSearchTerm)[1].split("\n")[0].contains("PSK"); + + Network::SECURITY_LEVEL securityLevel = Network::SECURITY_LEVEL::UNSUPPORTED; + + if (isPersonal && isCCMP) + securityLevel = Network::SECURITY_LEVEL::WPA2_AES_PERSONAL; + else if (isEnterprise && isCCMP) + securityLevel = Network::SECURITY_LEVEL::WPA2_AES_ENTERPRISE; + // TODO: Add support for the other security levels + + Network network(macAddress,ssid, securityLevel, Network::STATUS::NOT_CONNECTED, signalLevel); + emit didAddNetwork(network); + } + } +} Index: sources/wifi/WifiInterface.h =================================================================== diff -u -re5a802bc26647388cfea4f1d46ae22570ec2dba3 -rea52cee2614f319804690a9b1d5091bed9676753 --- sources/wifi/WifiInterface.h (.../WifiInterface.h) (revision e5a802bc26647388cfea4f1d46ae22570ec2dba3) +++ sources/wifi/WifiInterface.h (.../WifiInterface.h) (revision ea52cee2614f319804690a9b1d5091bed9676753) @@ -6,6 +6,7 @@ // Project #include "main.h" +#include "Network.h" // define #define _WifiInterface WifiInterface::I() @@ -40,7 +41,12 @@ bool doInit(); void doScan(); +signals: + void didAddNetwork(const Network); + void didScanStatusChanged(const bool); + private slots: void onQuit(); void onScanFinished(int, QProcess::ExitStatus); + void onParseWifiScan(const QString &output); };