Merge branch 'master' of https://git.itsblue.de/Fenoglio/omobileddisplay
This commit is contained in:
commit
ccc04d1852
20 changed files with 392 additions and 34 deletions
|
@ -1,7 +1,8 @@
|
||||||
QT += quick bluetooth quickcontrols2
|
QT += quick bluetooth quickcontrols2
|
||||||
CONFIG += c++11
|
CONFIG += c++11
|
||||||
|
|
||||||
TARGET = OmobiDisplayApp
|
TARGET = ItsblueLedDisplayController
|
||||||
|
VERSION = 1.0.0
|
||||||
|
|
||||||
TEMPLATE = app
|
TEMPLATE = app
|
||||||
|
|
||||||
|
@ -41,18 +42,24 @@ CONFIG += QBluetoothLeUart_QML
|
||||||
include($$PWD/QBluetoothLeUart/QBluetoothLeUart.pri)
|
include($$PWD/QBluetoothLeUart/QBluetoothLeUart.pri)
|
||||||
|
|
||||||
DISTFILES += \
|
DISTFILES += \
|
||||||
test.qmodel
|
android/AndroidManifest.xml
|
||||||
|
|
||||||
STATECHARTS +=
|
android {
|
||||||
|
QT += androidextras
|
||||||
contains(ANDROID_TARGET_ARCH,armeabi-v7a) {
|
ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android
|
||||||
ANDROID_ABIS = \
|
|
||||||
armeabi-v7a
|
|
||||||
}
|
|
||||||
|
|
||||||
ANDROID_ABIS = armeabi-v7a
|
|
||||||
|
|
||||||
contains(ANDROID_TARGET_ARCH,) {
|
contains(ANDROID_TARGET_ARCH,) {
|
||||||
ANDROID_ABIS = \
|
ANDROID_ABIS = \
|
||||||
armeabi-v7a
|
armeabi-v7a
|
||||||
}
|
}
|
||||||
|
|
||||||
|
contains(ANDROID_TARGET_ARCH,armeabi-v7a) {
|
||||||
|
ANDROID_ABIS = \
|
||||||
|
armeabi-v7a
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contains(ANDROID_TARGET_ARCH,armeabi-v7a) {
|
||||||
|
ANDROID_ABIS = \
|
||||||
|
armeabi-v7a
|
||||||
|
}
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 76e457593e889885fd410fdbcdd659706a1eceb8
|
Subproject commit fba59b37770ab1ede351ec70119d2da328be6a06
|
82
OmobiDisplayApp/android/AndroidManifest.xml
Normal file
82
OmobiDisplayApp/android/AndroidManifest.xml
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<manifest package="de.itsblue.LedDisplayController" xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="1.0" android:versionCode="1" android:installLocation="auto">
|
||||||
|
<!-- The following comment will be replaced upon deployment with default permissions based on the dependencies of the application.
|
||||||
|
Remove the comment if you do not require these default permissions. -->
|
||||||
|
<uses-permission android:name="android.permission.INTERNET"/>
|
||||||
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
|
||||||
|
<uses-permission android:name="android.permission.BLUETOOTH"/>
|
||||||
|
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
|
||||||
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||||
|
|
||||||
|
<!-- The following comment will be replaced upon deployment with default features based on the dependencies of the application.
|
||||||
|
Remove the comment if you do not require these default features. -->
|
||||||
|
|
||||||
|
|
||||||
|
<supports-screens android:largeScreens="true" android:normalScreens="true" android:anyDensity="true" android:smallScreens="true"/>
|
||||||
|
<application android:hardwareAccelerated="true" android:name="org.qtproject.qt5.android.bindings.QtApplication" android:label="ItsblueLedDisplayController" android:extractNativeLibs="true">
|
||||||
|
<activity android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density" android:name="org.qtproject.qt5.android.bindings.QtActivity" android:label="ItsblueLedDisplayController" android:screenOrientation="unspecified" android:launchMode="singleTop">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN"/>
|
||||||
|
<category android:name="android.intent.category.LAUNCHER"/>
|
||||||
|
</intent-filter>
|
||||||
|
<!-- Application arguments -->
|
||||||
|
<!-- meta-data android:name="android.app.arguments" android:value="arg1 arg2 arg3"/ -->
|
||||||
|
<!-- Application arguments -->
|
||||||
|
<meta-data android:name="android.app.lib_name" android:value="ItsblueLedDisplayController"/>
|
||||||
|
<meta-data android:name="android.app.qt_sources_resource_id" android:resource="@array/qt_sources"/>
|
||||||
|
<meta-data android:name="android.app.repository" android:value="default"/>
|
||||||
|
<meta-data android:name="android.app.qt_libs_resource_id" android:resource="@array/qt_libs"/>
|
||||||
|
<meta-data android:name="android.app.bundled_libs_resource_id" android:resource="@array/bundled_libs"/>
|
||||||
|
<!-- Deploy Qt libs as part of package -->
|
||||||
|
<meta-data android:name="android.app.bundle_local_qt_libs" android:value="1"/>
|
||||||
|
<!-- Run with local libs -->
|
||||||
|
<meta-data android:name="android.app.use_local_qt_libs" android:value="1"/>
|
||||||
|
<meta-data android:name="android.app.libs_prefix" android:value="/data/local/tmp/qt/"/>
|
||||||
|
<meta-data android:name="android.app.load_local_libs_resource_id" android:resource="@array/load_local_libs"/>
|
||||||
|
<meta-data android:name="android.app.load_local_jars" android:value="jar/QtAndroid.jar:jar/QtAndroidExtras.jar:jar/QtAndroidBluetooth.jar:jar/QtAndroidBearer.jar"/>
|
||||||
|
<meta-data android:name="android.app.static_init_classes" android:value="org.qtproject.qt5.android.bluetooth.QtBluetoothBroadcastReceiver"/>
|
||||||
|
<!-- Used to specify custom system library path to run with local system libs -->
|
||||||
|
<!-- <meta-data android:name="android.app.system_libs_prefix" android:value="/system/lib/"/> -->
|
||||||
|
<!-- Messages maps -->
|
||||||
|
<meta-data android:value="@string/ministro_not_found_msg" android:name="android.app.ministro_not_found_msg"/>
|
||||||
|
<meta-data android:value="@string/ministro_needed_msg" android:name="android.app.ministro_needed_msg"/>
|
||||||
|
<meta-data android:value="@string/fatal_error_msg" android:name="android.app.fatal_error_msg"/>
|
||||||
|
<meta-data android:value="@string/unsupported_android_version" android:name="android.app.unsupported_android_version"/>
|
||||||
|
<!-- Messages maps -->
|
||||||
|
<!-- Splash screen -->
|
||||||
|
<!-- Orientation-specific (portrait/landscape) data is checked first. If not available for current orientation,
|
||||||
|
then android.app.splash_screen_drawable. For best results, use together with splash_screen_sticky and
|
||||||
|
use hideSplashScreen() with a fade-out animation from Qt Android Extras to hide the splash screen when you
|
||||||
|
are done populating your window with content. -->
|
||||||
|
<!-- meta-data android:name="android.app.splash_screen_drawable_portrait" android:resource="@drawable/logo_portrait" / -->
|
||||||
|
<!-- meta-data android:name="android.app.splash_screen_drawable_landscape" android:resource="@drawable/logo_landscape" / -->
|
||||||
|
<!-- meta-data android:name="android.app.splash_screen_drawable" android:resource="@drawable/logo"/ -->
|
||||||
|
<!-- meta-data android:name="android.app.splash_screen_sticky" android:value="true"/ -->
|
||||||
|
<!-- Splash screen -->
|
||||||
|
<!-- Background running -->
|
||||||
|
<!-- Warning: changing this value to true may cause unexpected crashes if the
|
||||||
|
application still try to draw after
|
||||||
|
"applicationStateChanged(Qt::ApplicationSuspended)"
|
||||||
|
signal is sent! -->
|
||||||
|
<meta-data android:name="android.app.background_running" android:value="false"/>
|
||||||
|
<!-- Background running -->
|
||||||
|
<!-- auto screen scale factor -->
|
||||||
|
<meta-data android:name="android.app.auto_screen_scale_factor" android:value="false"/>
|
||||||
|
<!-- auto screen scale factor -->
|
||||||
|
<!-- extract android style -->
|
||||||
|
<!-- available android:values :
|
||||||
|
* default - In most cases this will be the same as "full", but it can also be something else if needed, e.g., for compatibility reasons
|
||||||
|
* full - useful QWidget & Quick Controls 1 apps
|
||||||
|
* minimal - useful for Quick Controls 2 apps, it is much faster than "full"
|
||||||
|
* none - useful for apps that don't use any of the above Qt modules
|
||||||
|
-->
|
||||||
|
<meta-data android:name="android.app.extract_android_style" android:value="default"/>
|
||||||
|
<!-- extract android style -->
|
||||||
|
</activity>
|
||||||
|
<!-- For adding service(s) please check: https://wiki.qt.io/AndroidServices -->
|
||||||
|
</application>
|
||||||
|
|
||||||
|
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="29"/>
|
||||||
|
</manifest>
|
|
@ -3,19 +3,33 @@
|
||||||
#include <QQuickStyle>
|
#include <QQuickStyle>
|
||||||
#include <qbluetoothleuartclient.h>
|
#include <qbluetoothleuartclient.h>
|
||||||
#include <QTranslator>
|
#include <QTranslator>
|
||||||
|
#include <QFontDatabase>
|
||||||
|
|
||||||
|
#ifdef Q_OS_ANDROID
|
||||||
|
#include <QtAndroidExtras>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "omobidisplaybackend.h"
|
#include "omobidisplaybackend.h"
|
||||||
#include "omobidisplaytextmodel.h"
|
#include "omobidisplaytextmodel.h"
|
||||||
|
|
||||||
|
/*void permissionCallback(const QtAndroid::PermissionResultMap& results) {
|
||||||
|
for(QtAndroid::PermissionResult result : results) {
|
||||||
|
qWarning() << "Permission Callback Result:" << (result == QtAndroid::PermissionResult::Granted);
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
|
||||||
|
|
||||||
|
QCoreApplication::setOrganizationName("Itsblue");
|
||||||
|
QCoreApplication::setOrganizationDomain("itsblue.de");
|
||||||
|
QCoreApplication::setApplicationName("Itsblue smart display");
|
||||||
|
|
||||||
QGuiApplication app(argc, argv);
|
QGuiApplication app(argc, argv);
|
||||||
|
|
||||||
QTranslator translator;
|
QTranslator translator;
|
||||||
translator.load(":/" + QLocale::system().name() + ".qm");
|
translator.load(":/" + QLocale::system().name() + ".qm");
|
||||||
translator.load(":/de.qm");
|
|
||||||
app.installTranslator(&translator);
|
app.installTranslator(&translator);
|
||||||
|
|
||||||
qmlRegisterType<OmobiDisplayBackend>("de.itsblue.omobidisplayapp", 1, 0, "OmobiDisplayBackend");
|
qmlRegisterType<OmobiDisplayBackend>("de.itsblue.omobidisplayapp", 1, 0, "OmobiDisplayBackend");
|
||||||
|
|
|
@ -9,6 +9,8 @@ OmobiDisplayBackend::OmobiDisplayBackend(QObject *parent) : QObject(parent)
|
||||||
this->displayBrightness = -1;
|
this->displayBrightness = -1;
|
||||||
this->waitingCommands = 0;
|
this->waitingCommands = 0;
|
||||||
|
|
||||||
|
this->settings = new QSettings();
|
||||||
|
|
||||||
this->keepAliveTimer = new QTimer(this);
|
this->keepAliveTimer = new QTimer(this);
|
||||||
this->keepAliveTimer->setInterval(5000);
|
this->keepAliveTimer->setInterval(5000);
|
||||||
this->keepAliveTimer->setSingleShot(false);
|
this->keepAliveTimer->setSingleShot(false);
|
||||||
|
@ -34,10 +36,24 @@ void OmobiDisplayBackend::startScanning() {
|
||||||
void OmobiDisplayBackend::authenticate(QString code) {
|
void OmobiDisplayBackend::authenticate(QString code) {
|
||||||
// tell display to send over existing model data
|
// tell display to send over existing model data
|
||||||
this->setState(Authenticating);
|
this->setState(Authenticating);
|
||||||
QString combinedCode = this->bleClient->getCurrentDevice()->getAddress().toUpper() + code;
|
|
||||||
QString secret = QCryptographicHash::hash(combinedCode.toUtf8(), QCryptographicHash::Sha256).toHex();
|
|
||||||
|
|
||||||
this->sendBluetoothCommand(AuthorizeSessionCommand, QVariantMap{{"secret", secret}});
|
if(code.length() == 64)
|
||||||
|
this->lastDisplaySecret = code;
|
||||||
|
else if(code.length() == 4) {
|
||||||
|
QString combinedCode = this->bleClient->getCurrentDevice()->getAddress().toUpper() + code;
|
||||||
|
this->lastDisplaySecret = QCryptographicHash::hash(combinedCode.toUtf8(), QCryptographicHash::Sha256).toHex();
|
||||||
|
}
|
||||||
|
|
||||||
|
this->sendBluetoothCommand(AuthenticateCommand, QVariantMap{{"secret", this->lastDisplaySecret}});
|
||||||
|
}
|
||||||
|
|
||||||
|
void OmobiDisplayBackend::handleBluetoothScanningError(QBluetoothLeUartClient::BluetoothScanError error) {
|
||||||
|
if(error == QBluetoothLeUartClient::LocationPermissionDeniedError) {
|
||||||
|
#ifdef Q_OS_ANDROID
|
||||||
|
// try to get permission
|
||||||
|
//QtAndroid::requestPermissions({"android.permission.ACCESS_FINE_LOCATION", "android.permission.ACCESS_COARSE_LOCATION"}, NULL);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OmobiDisplayBackend::handleBluetoothStateChange(QBluetoothLeUartClient::BluetoothLeUartClientState state){
|
void OmobiDisplayBackend::handleBluetoothStateChange(QBluetoothLeUartClient::BluetoothLeUartClientState state){
|
||||||
|
@ -46,6 +62,14 @@ void OmobiDisplayBackend::handleBluetoothStateChange(QBluetoothLeUartClient::Blu
|
||||||
this->setState(Idle);
|
this->setState(Idle);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case QBluetoothLeUartClient::AdapterTurnedOff: {
|
||||||
|
this->setState(BluetoothOff);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QBluetoothLeUartClient::LocationPermissionDenied: {
|
||||||
|
this->setState(LocationPermissionDenied);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case QBluetoothLeUartClient::Scanning: {
|
case QBluetoothLeUartClient::Scanning: {
|
||||||
this->setState(Scanning);
|
this->setState(Scanning);
|
||||||
break;
|
break;
|
||||||
|
@ -79,9 +103,10 @@ void OmobiDisplayBackend::handleBluetoothStateChange(QBluetoothLeUartClient::Blu
|
||||||
}
|
}
|
||||||
|
|
||||||
void OmobiDisplayBackend::handleBluetoothDeviceConected() {
|
void OmobiDisplayBackend::handleBluetoothDeviceConected() {
|
||||||
this->setState(AuthenticationRequired);
|
if(this->settings->contains(this->bleClient->getCurrentDevice()->getAddress()))
|
||||||
this->authenticate("1234");
|
this->authenticate(this->settings->value(this->bleClient->getCurrentDevice()->getAddress()).toString());
|
||||||
// TODO: stuff
|
else
|
||||||
|
this->setState(AuthenticationRequired);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OmobiDisplayBackend::handleFoundNewDevice(QBluetoothLeUartDevice* device) {
|
void OmobiDisplayBackend::handleFoundNewDevice(QBluetoothLeUartDevice* device) {
|
||||||
|
@ -118,7 +143,7 @@ void OmobiDisplayBackend::sendBluetoothCommand(OmobiDisplayCommand command, QVar
|
||||||
|
|
||||||
QJsonDocument doc = QJsonDocument::fromVariant(commandMap);
|
QJsonDocument doc = QJsonDocument::fromVariant(commandMap);
|
||||||
|
|
||||||
qDebug() << "Sending command: \n" << qPrintable(doc.toJson(QJsonDocument::Indented));
|
//qDebug() << "Sending command: \n" << qPrintable(doc.toJson(QJsonDocument::Indented));
|
||||||
|
|
||||||
this->waitingCommands ++;
|
this->waitingCommands ++;
|
||||||
|
|
||||||
|
@ -131,13 +156,13 @@ void OmobiDisplayBackend::sendBluetoothCommand(OmobiDisplayCommand command, QVar
|
||||||
void OmobiDisplayBackend::sendBluetoothKeepAlive() {
|
void OmobiDisplayBackend::sendBluetoothKeepAlive() {
|
||||||
QJsonDocument doc = QJsonDocument::fromVariant(QVariantMap{{"header", KeepAliveCommand}});
|
QJsonDocument doc = QJsonDocument::fromVariant(QVariantMap{{"header", KeepAliveCommand}});
|
||||||
|
|
||||||
qDebug() << "Sending keep alive: \n" << qPrintable(doc.toJson(QJsonDocument::Indented));
|
//qDebug() << "Sending keep alive: \n" << qPrintable(doc.toJson(QJsonDocument::Indented));
|
||||||
|
|
||||||
this->bleClient->sendData(doc.toJson(QJsonDocument::Compact));
|
this->bleClient->sendData(doc.toJson(QJsonDocument::Compact));
|
||||||
}
|
}
|
||||||
|
|
||||||
void OmobiDisplayBackend::handleBluetoothDataReceived(QString s){
|
void OmobiDisplayBackend::handleBluetoothDataReceived(QString s){
|
||||||
qDebug() << "New data: \n" << qPrintable(s);
|
//qDebug() << "New data: \n" << qPrintable(s);
|
||||||
|
|
||||||
QJsonParseError parseError;
|
QJsonParseError parseError;
|
||||||
QJsonDocument doc = QJsonDocument::fromJson(s.toUtf8(), &parseError);
|
QJsonDocument doc = QJsonDocument::fromJson(s.toUtf8(), &parseError);
|
||||||
|
@ -150,12 +175,15 @@ void OmobiDisplayBackend::handleBluetoothDataReceived(QString s){
|
||||||
OmobiDisplayStatusCode status = OmobiDisplayStatusCode(doc.toVariant().toMap()["status"].toInt());
|
OmobiDisplayStatusCode status = OmobiDisplayStatusCode(doc.toVariant().toMap()["status"].toInt());
|
||||||
|
|
||||||
switch (header) {
|
switch (header) {
|
||||||
case AuthorizeSessionCommand: {
|
case AuthenticateCommand: {
|
||||||
if(status != Success) {
|
if(status != Success) {
|
||||||
this->setState(AuthenticationRequired);
|
this->setState(AuthenticationRequired);
|
||||||
|
this->lastDisplaySecret = "";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this->settings->setValue(this->bleClient->getCurrentDevice()->getAddress(), this->lastDisplaySecret);
|
||||||
|
|
||||||
this->waitingCommands = 0;
|
this->waitingCommands = 0;
|
||||||
this->setState(Initing);
|
this->setState(Initing);
|
||||||
this->sendBluetoothCommand(GetAllTextSetsCommand);
|
this->sendBluetoothCommand(GetAllTextSetsCommand);
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
#include <QCryptographicHash>
|
#include <QCryptographicHash>
|
||||||
|
#include <QSettings>
|
||||||
|
|
||||||
#include <qbluetoothleuartclient.h>
|
#include <qbluetoothleuartclient.h>
|
||||||
#include <omobidisplaytextmodel.h>
|
#include <omobidisplaytextmodel.h>
|
||||||
|
@ -22,6 +23,8 @@ public:
|
||||||
|
|
||||||
enum OmobiDisplayAppState {
|
enum OmobiDisplayAppState {
|
||||||
Idle,
|
Idle,
|
||||||
|
BluetoothOff,
|
||||||
|
LocationPermissionDenied,
|
||||||
Scanning,
|
Scanning,
|
||||||
ReadyToConnect,
|
ReadyToConnect,
|
||||||
Connecting,
|
Connecting,
|
||||||
|
@ -35,7 +38,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum OmobiDisplayCommand {
|
enum OmobiDisplayCommand {
|
||||||
AuthorizeSessionCommand = 0,
|
AuthenticateCommand = 0,
|
||||||
KeepAliveCommand = 1,
|
KeepAliveCommand = 1,
|
||||||
GetAllTextSetsCommand = 10,
|
GetAllTextSetsCommand = 10,
|
||||||
GetTextSetParameterCommand = 11,
|
GetTextSetParameterCommand = 11,
|
||||||
|
@ -59,6 +62,9 @@ private:
|
||||||
QList<QMap<int, QVariant>> textSetsBuffer;
|
QList<QMap<int, QVariant>> textSetsBuffer;
|
||||||
int displayBrightness;
|
int displayBrightness;
|
||||||
|
|
||||||
|
QSettings* settings;
|
||||||
|
QString lastDisplaySecret;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
Q_INVOKABLE void startScanning();
|
Q_INVOKABLE void startScanning();
|
||||||
Q_INVOKABLE void authenticate(QString secret);
|
Q_INVOKABLE void authenticate(QString secret);
|
||||||
|
@ -74,6 +80,7 @@ private slots:
|
||||||
void handleBluetoothStateChange(QBluetoothLeUartClient::BluetoothLeUartClientState state);
|
void handleBluetoothStateChange(QBluetoothLeUartClient::BluetoothLeUartClientState state);
|
||||||
void handleFoundNewDevice(QBluetoothLeUartDevice* device);
|
void handleFoundNewDevice(QBluetoothLeUartDevice* device);
|
||||||
void handleBluetoothDeviceConected();
|
void handleBluetoothDeviceConected();
|
||||||
|
void handleBluetoothScanningError(QBluetoothLeUartClient::BluetoothScanError error);
|
||||||
|
|
||||||
void handleDisplayTextModelDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles = QVector<int>());
|
void handleDisplayTextModelDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles = QVector<int>());
|
||||||
void handleDisplayTextModelRowsInserted(const QModelIndex &parent, int first, int last);
|
void handleDisplayTextModelRowsInserted(const QModelIndex &parent, int first, int last);
|
||||||
|
|
|
@ -9,7 +9,6 @@ OmobiDisplayTextModel::OmobiDisplayTextModel(QObject* parent) : QAbstractListMod
|
||||||
connect(this, &OmobiDisplayTextModel::rowsRemoved, this, &OmobiDisplayTextModel::rowCountChanged);
|
connect(this, &OmobiDisplayTextModel::rowsRemoved, this, &OmobiDisplayTextModel::rowCountChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int OmobiDisplayTextModel::rowCount(const QModelIndex &) const
|
int OmobiDisplayTextModel::rowCount(const QModelIndex &) const
|
||||||
{
|
{
|
||||||
return this->texts.length();
|
return this->texts.length();
|
||||||
|
|
|
@ -16,6 +16,11 @@ Page {
|
||||||
|
|
||||||
title: qsTr("Available displays")
|
title: qsTr("Available displays")
|
||||||
|
|
||||||
|
signal opened()
|
||||||
|
|
||||||
|
onOpened: {
|
||||||
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
id: mainLayout
|
id: mainLayout
|
||||||
anchors {
|
anchors {
|
||||||
|
@ -114,6 +119,7 @@ Page {
|
||||||
}
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
|
id: noDisplaysItem
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
|
|
||||||
width: Math.min(parent.height, parent.width)
|
width: Math.min(parent.height, parent.width)
|
||||||
|
@ -167,6 +173,123 @@ Page {
|
||||||
text: parseInt(root.state) === OmobiDisplayBackend.Scanning ? qsTr("Still scanning"):qsTr("No displays found")
|
text: parseInt(root.state) === OmobiDisplayBackend.Scanning ? qsTr("Still scanning"):qsTr("No displays found")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: bluetoothOffItem
|
||||||
|
anchors.centerIn: parent
|
||||||
|
|
||||||
|
width: Math.min(parent.height, parent.width)
|
||||||
|
height: Math.min(parent.height, parent.width)
|
||||||
|
|
||||||
|
opacity: 0
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
NumberAnimation {}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: bluetoothOffIcon
|
||||||
|
anchors {
|
||||||
|
top: parent.top
|
||||||
|
topMargin: parent.height * 0.1
|
||||||
|
horizontalCenter: parent.horizontalCenter
|
||||||
|
}
|
||||||
|
anchors.verticalCenterOffset: text === "..." ? -height * 0.25:0
|
||||||
|
color: "lightgrey"
|
||||||
|
font.pixelSize: parent.height * 0.4
|
||||||
|
font.family: fontAwesomeBrands.name
|
||||||
|
text: "\uf294"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: bluetoothOffText
|
||||||
|
anchors {
|
||||||
|
top: bluetoothOffIcon.bottom
|
||||||
|
topMargin: bluetoothOffIcon.height * 0.15
|
||||||
|
horizontalCenter: parent.horizontalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
font.bold: true
|
||||||
|
font.pixelSize: bluetoothOffIcon.height * 0.15
|
||||||
|
|
||||||
|
color: Qt.darker("lightgrey", 1.1)
|
||||||
|
text: qsTr("Bluetooth is turned off")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: noPermissionItem
|
||||||
|
anchors.centerIn: parent
|
||||||
|
|
||||||
|
width: Math.min(parent.height, parent.width)
|
||||||
|
height: Math.min(parent.height, parent.width)
|
||||||
|
|
||||||
|
opacity: 0
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
NumberAnimation {}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: noPermissionIcon
|
||||||
|
anchors {
|
||||||
|
top: parent.top
|
||||||
|
topMargin: parent.height * 0
|
||||||
|
horizontalCenter: parent.horizontalCenter
|
||||||
|
}
|
||||||
|
anchors.verticalCenterOffset: text === "..." ? -height * 0.25:0
|
||||||
|
color: "lightgrey"
|
||||||
|
font.pixelSize: parent.height * 0.4
|
||||||
|
font.family: fontAwesome.name
|
||||||
|
text: "\uf3ed"
|
||||||
|
}
|
||||||
|
Text {
|
||||||
|
id: noPermissionText
|
||||||
|
anchors {
|
||||||
|
top: noPermissionIcon.bottom
|
||||||
|
topMargin: noPermissionIcon.height * 0.15
|
||||||
|
horizontalCenter: parent.horizontalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
width: parent.width * 0.9
|
||||||
|
|
||||||
|
font.bold: true
|
||||||
|
font.pixelSize: noPermissionIcon.height * 0.15
|
||||||
|
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
|
||||||
|
wrapMode: Text.Wrap
|
||||||
|
|
||||||
|
color: Qt.darker("lightgrey", 1.1)
|
||||||
|
text: qsTr("Error:\nLocation permission denied!")
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: noPermissionDetailText
|
||||||
|
anchors {
|
||||||
|
top: noPermissionText.bottom
|
||||||
|
topMargin: noPermissionText.height * 0.15
|
||||||
|
horizontalCenter: parent.horizontalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
width: parent.width * 0.9
|
||||||
|
|
||||||
|
font.bold: true
|
||||||
|
font.pixelSize: noPermissionText.font.pixelSize * 0.7
|
||||||
|
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
|
||||||
|
wrapMode: Text.Wrap
|
||||||
|
|
||||||
|
color: Qt.darker("lightgrey", 1.1)
|
||||||
|
text: qsTr("This app requires location permission in order for Bluetooth to work, it will not actually access your location.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,6 +341,44 @@ Page {
|
||||||
statusText: qsTr("Tap here to scan")
|
statusText: qsTr("Tap here to scan")
|
||||||
working: false
|
working: false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
target: noPermissionItem
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: OmobiDisplayBackend.BluetoothOff
|
||||||
|
PropertyChanges {
|
||||||
|
target: bluetoothOffItem
|
||||||
|
opacity: 1
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: root
|
||||||
|
statusText: qsTr("Bluetooth is turned off")
|
||||||
|
working: false
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: noDisplaysItem
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
State {
|
||||||
|
name: OmobiDisplayBackend.LocationPermissionDenied
|
||||||
|
|
||||||
|
PropertyChanges {
|
||||||
|
target: noPermissionItem
|
||||||
|
opacity: 1
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: root
|
||||||
|
statusText: qsTr("Tap here to continue")
|
||||||
|
working: false
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: noDisplaysItem
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
},
|
},
|
||||||
State {
|
State {
|
||||||
name: OmobiDisplayBackend.Scanning
|
name: OmobiDisplayBackend.Scanning
|
||||||
|
@ -227,6 +388,14 @@ Page {
|
||||||
statusText: qsTr("Scanning...")
|
statusText: qsTr("Scanning...")
|
||||||
working: true
|
working: true
|
||||||
}
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: bluetoothOffItem
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
|
PropertyChanges {
|
||||||
|
target: noPermissionItem
|
||||||
|
opacity: 0
|
||||||
|
}
|
||||||
},
|
},
|
||||||
State {
|
State {
|
||||||
name: OmobiDisplayBackend.ReadyToConnect
|
name: OmobiDisplayBackend.ReadyToConnect
|
||||||
|
|
|
@ -15,6 +15,8 @@ Page {
|
||||||
|
|
||||||
title: backend.bleClient.currentDevice === null ? "":backend.bleClient.currentDevice.name
|
title: backend.bleClient.currentDevice === null ? "":backend.bleClient.currentDevice.name
|
||||||
|
|
||||||
|
signal opened()
|
||||||
|
|
||||||
function backButtonClicked() {
|
function backButtonClicked() {
|
||||||
backend.bleClient.disconnectFromDevice()
|
backend.bleClient.disconnectFromDevice()
|
||||||
}
|
}
|
||||||
|
@ -50,15 +52,17 @@ Page {
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
font.pixelSize: parent.height * 0.5
|
font.pixelSize: parent.height * 0.5
|
||||||
|
font.family: fontAwesome.name
|
||||||
text: "\uf186"
|
text: "\uf186"
|
||||||
}
|
}
|
||||||
|
|
||||||
Slider {
|
Slider {
|
||||||
|
id: brightnessSlider
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
|
|
||||||
from: 0
|
from: 0
|
||||||
to: 10
|
to: 255
|
||||||
stepSize: 1
|
stepSize: 1
|
||||||
|
|
||||||
value: backend.displayBrightness
|
value: backend.displayBrightness
|
||||||
|
@ -67,12 +71,19 @@ Page {
|
||||||
if(!pressed)
|
if(!pressed)
|
||||||
backend.displayBrightness = value
|
backend.displayBrightness = value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ToolTip {
|
||||||
|
parent: brightnessSlider.handle
|
||||||
|
visible: brightnessSlider.pressed
|
||||||
|
text: brightnessSlider.value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Text {
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
font.pixelSize: parent.height * 0.5
|
font.pixelSize: parent.height * 0.5
|
||||||
|
font.family: fontAwesome.name
|
||||||
text: "\uf185"
|
text: "\uf185"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ ItemDelegate {
|
||||||
property string value: ""
|
property string value: ""
|
||||||
property alias from: spinBox.from
|
property alias from: spinBox.from
|
||||||
property alias to: spinBox.to
|
property alias to: spinBox.to
|
||||||
|
property bool editable: false
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
spinBox.value = control.value
|
spinBox.value = control.value
|
||||||
|
@ -67,6 +68,7 @@ ItemDelegate {
|
||||||
contentItem: SpinBox {
|
contentItem: SpinBox {
|
||||||
id: spinBox
|
id: spinBox
|
||||||
value: control.value
|
value: control.value
|
||||||
|
editable: control.editable
|
||||||
}
|
}
|
||||||
|
|
||||||
onAccepted: {
|
onAccepted: {
|
||||||
|
|
|
@ -82,6 +82,8 @@ Dialog {
|
||||||
SpinBoxDelegate {
|
SpinBoxDelegate {
|
||||||
id: runtimeSpinBox
|
id: runtimeSpinBox
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
editable: true
|
||||||
|
to: 3600
|
||||||
text: qsTr("Runtime (in s)")
|
text: qsTr("Runtime (in s)")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,7 +109,7 @@ Dialog {
|
||||||
SpinBoxDelegate {
|
SpinBoxDelegate {
|
||||||
id: scrollSpeedSpinBox
|
id: scrollSpeedSpinBox
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
from: 0
|
from: 1
|
||||||
to: 10
|
to: 10
|
||||||
text: qsTr("Scroll speed")
|
text: qsTr("Scroll speed")
|
||||||
}
|
}
|
||||||
|
@ -116,6 +118,7 @@ Dialog {
|
||||||
id: scrollCountSpinBox
|
id: scrollCountSpinBox
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
from: 0
|
from: 0
|
||||||
|
editable: true
|
||||||
text: qsTr("Scroll count")
|
text: qsTr("Scroll count")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,7 @@ ApplicationWindow {
|
||||||
|
|
||||||
opacity: mainStack.currentItem.backButtonVisible ? 1:0
|
opacity: mainStack.currentItem.backButtonVisible ? 1:0
|
||||||
|
|
||||||
font.styleName: fontAwesome.name
|
font.family: fontAwesome.name
|
||||||
font.pixelSize: height * 0.6
|
font.pixelSize: height * 0.6
|
||||||
Material.foreground: "black"
|
Material.foreground: "black"
|
||||||
|
|
||||||
|
@ -63,7 +63,7 @@ ApplicationWindow {
|
||||||
onClicked: mainStack.currentItem.backButtonClicked()
|
onClicked: mainStack.currentItem.backButtonClicked()
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
Label {
|
||||||
Layout.fillHeight: true
|
Layout.fillHeight: true
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.alignment: Layout.Center
|
Layout.alignment: Layout.Center
|
||||||
|
@ -71,6 +71,7 @@ ApplicationWindow {
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
|
||||||
|
color: "black"
|
||||||
text: mainStack.currentItem.title
|
text: mainStack.currentItem.title
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,7 +83,7 @@ ApplicationWindow {
|
||||||
|
|
||||||
opacity: mainStack.currentItem.actionButtonVisible ? 1:0
|
opacity: mainStack.currentItem.actionButtonVisible ? 1:0
|
||||||
|
|
||||||
font.styleName: fontAwesome.name
|
font.family: fontAwesome.name
|
||||||
font.pixelSize: height * 0.4
|
font.pixelSize: height * 0.4
|
||||||
Material.foreground: "black"
|
Material.foreground: "black"
|
||||||
|
|
||||||
|
@ -102,7 +103,20 @@ ApplicationWindow {
|
||||||
|
|
||||||
FontLoader {
|
FontLoader {
|
||||||
id: fontAwesome
|
id: fontAwesome
|
||||||
source: "qrc:/fa5regular.woff"
|
source: "qrc:/fa5solid.woff"
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
console.log("Font name: " + fontAwesome.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FontLoader {
|
||||||
|
id: fontAwesomeBrands
|
||||||
|
source: "qrc:/fa5brands.woff"
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
console.log("Font name: " + fontAwesome.name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StackView {
|
StackView {
|
||||||
|
@ -117,6 +131,10 @@ ApplicationWindow {
|
||||||
mainStack.replace(currentComponent)
|
mainStack.replace(currentComponent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onCurrentItemChanged: {
|
||||||
|
currentItem.opened()
|
||||||
|
}
|
||||||
|
|
||||||
initialItem: connectedPageComp
|
initialItem: connectedPageComp
|
||||||
|
|
||||||
replaceEnter: Transition {
|
replaceEnter: Transition {
|
||||||
|
@ -160,6 +178,22 @@ ApplicationWindow {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
State {
|
||||||
|
name: OmobiDisplayBackend.BluetoothOff
|
||||||
|
PropertyChanges {
|
||||||
|
target: mainStack
|
||||||
|
currentComponent: connectPageComp
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
State {
|
||||||
|
name: OmobiDisplayBackend.LocationPermissionDenied
|
||||||
|
PropertyChanges {
|
||||||
|
target: mainStack
|
||||||
|
currentComponent: connectPageComp
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
State {
|
State {
|
||||||
name: OmobiDisplayBackend.Scanning
|
name: OmobiDisplayBackend.Scanning
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
|
|
BIN
OmobiDisplayApp/ressources/shared/fa5brands.woff
Normal file
BIN
OmobiDisplayApp/ressources/shared/fa5brands.woff
Normal file
Binary file not shown.
Binary file not shown.
BIN
OmobiDisplayApp/ressources/shared/fa5solid.woff
Normal file
BIN
OmobiDisplayApp/ressources/shared/fa5solid.woff
Normal file
Binary file not shown.
|
@ -2,6 +2,7 @@
|
||||||
<qresource prefix="/">
|
<qresource prefix="/">
|
||||||
<file>omobi.png</file>
|
<file>omobi.png</file>
|
||||||
<file>itsblue.png</file>
|
<file>itsblue.png</file>
|
||||||
<file>fa5regular.woff</file>
|
<file>fa5solid.woff</file>
|
||||||
|
<file>fa5brands.woff</file>
|
||||||
</qresource>
|
</qresource>
|
||||||
</RCC>
|
</RCC>
|
||||||
|
|
Binary file not shown.
|
@ -76,7 +76,8 @@
|
||||||
<message>
|
<message>
|
||||||
<source>Display name
|
<source>Display name
|
||||||
(needs restart)</source>
|
(needs restart)</source>
|
||||||
<translation>Displayname\n(neutstart nötig)</translation>
|
<translation>Displayname
|
||||||
|
(neutstart nötig)</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<source>Display code (4 digits)</source>
|
<source>Display code (4 digits)</source>
|
||||||
|
|
|
@ -50,7 +50,7 @@ protected:
|
||||||
private:
|
private:
|
||||||
enum OmobiDisplayCommand
|
enum OmobiDisplayCommand
|
||||||
{
|
{
|
||||||
AuthorizeSessionCommand = 0,
|
AuthenticateCommand = 0,
|
||||||
KeepAliveCommand = 1,
|
KeepAliveCommand = 1,
|
||||||
GetAllTextSetsCommand = 10,
|
GetAllTextSetsCommand = 10,
|
||||||
GetTextSetParameterCommand = 11,
|
GetTextSetParameterCommand = 11,
|
||||||
|
|
|
@ -53,7 +53,7 @@ void OmobiLedDisplay::onDataReceived(String dataString)
|
||||||
else
|
else
|
||||||
switch (requestHeader)
|
switch (requestHeader)
|
||||||
{
|
{
|
||||||
case AuthorizeSessionCommand:
|
case AuthenticateCommand:
|
||||||
{
|
{
|
||||||
String combinedCode = this->bleServer->getDeviceAddress() + String(this->properties.deviceCode);
|
String combinedCode = this->bleServer->getDeviceAddress() + String(this->properties.deviceCode);
|
||||||
String secret = this->sha256(combinedCode);
|
String secret = this->sha256(combinedCode);
|
||||||
|
|
Loading…
Reference in a new issue