This commit is contained in:
Jens Noack 2020-10-18 15:11:11 +02:00
commit ccc04d1852
20 changed files with 392 additions and 34 deletions

View file

@ -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

View 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>

View file

@ -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");

View file

@ -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);

View file

@ -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);

View file

@ -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();

View file

@ -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

View file

@ -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"
} }
} }

View file

@ -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: {

View file

@ -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")
} }
} }

View file

@ -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 {

Binary file not shown.

Binary file not shown.

View file

@ -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>

View file

@ -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>

View file

@ -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,

View file

@ -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);