diff --git a/OmobiDisplayApp/OmobiDisplayApp.pro b/OmobiDisplayApp/OmobiDisplayApp.pro index 696c527..900cbb2 100644 --- a/OmobiDisplayApp/OmobiDisplayApp.pro +++ b/OmobiDisplayApp/OmobiDisplayApp.pro @@ -1,4 +1,4 @@ -QT += quick bluetooth +QT += quick bluetooth quickcontrols2 CONFIG += c++11 TARGET = OmobiDisplayApp diff --git a/OmobiDisplayApp/omobidisplaybackend.cpp b/OmobiDisplayApp/omobidisplaybackend.cpp index 48602cd..b9dbcc4 100644 --- a/OmobiDisplayApp/omobidisplaybackend.cpp +++ b/OmobiDisplayApp/omobidisplaybackend.cpp @@ -209,16 +209,14 @@ void OmobiDisplayBackend::handleBluetoothDataReceived(QString s){ this->refreshLoadingState(); break; } - case SetTextSetParameterCommand: { + case SetTextSetParameterCommand: + case SetDisplayBrightnessCommand: + case SetDisplayCodeCommand: + case SetDisplayNameCommand: // TODO: Error handling this->refreshLoadingState(); break; - } - case SetDisplayBrightnessCommand: { - // TODO: Error handling - this->refreshLoadingState(); - break; - } + } } @@ -296,3 +294,13 @@ void OmobiDisplayBackend::setDisplayBrightness(int brightness) { emit this->displayBrightnessChanged(); } + + +void OmobiDisplayBackend::setDisplayCode(QString code) { + this->sendBluetoothCommand(SetDisplayCodeCommand, QVariantMap{{"displayCode",code}}); +} + +void OmobiDisplayBackend::setDisplayName(QString name) { + // This will restart the display!! + this->sendBluetoothCommand(SetDisplayNameCommand, QVariantMap{{"displayName", name}}); +} diff --git a/OmobiDisplayApp/omobidisplaybackend.h b/OmobiDisplayApp/omobidisplaybackend.h index f9a5fec..377fe2a 100644 --- a/OmobiDisplayApp/omobidisplaybackend.h +++ b/OmobiDisplayApp/omobidisplaybackend.h @@ -41,7 +41,9 @@ private: GetTextSetParameterCommand = 11, GetDisplayBrightnessCommand = 12, SetTextSetParameterCommand = 20, - SetDisplayBrightnessCommand = 21 + SetDisplayBrightnessCommand = 21, + SetDisplayCodeCommand = 22, + SetDisplayNameCommand = 23 }; enum OmobiDisplayStatusCode { @@ -65,6 +67,8 @@ public slots: Q_INVOKABLE OmobiDisplayTextModel* getDisplayTextModel(); Q_INVOKABLE int getDisplayBrightness(); Q_INVOKABLE void setDisplayBrightness(int brightness); + Q_INVOKABLE void setDisplayCode(QString code); + Q_INVOKABLE void setDisplayName(QString name); private slots: void handleBluetoothStateChange(QBluetoothLeUart::BluetoothLeUartState state); diff --git a/OmobiDisplayApp/ressources/qml/Chip.qml b/OmobiDisplayApp/ressources/qml/Chip.qml index 32ce03b..601f1e0 100644 --- a/OmobiDisplayApp/ressources/qml/Chip.qml +++ b/OmobiDisplayApp/ressources/qml/Chip.qml @@ -1,6 +1,10 @@ import QtQuick 2.12 import QtQuick.Controls 2.12 import QtGraphicalEffects 1.12 +import QtQuick.Templates 2.12 as T +import QtQuick.Controls.impl 2.12 +import QtQuick.Controls.Material 2.12 +import QtQuick.Controls.Material.impl 2.12 Item { id: control @@ -15,6 +19,7 @@ Item { property bool glowVisible: true property double glowScale: 0.9 property double glowOpacity: Math.pow( control.opacity, 100 ) + property bool interactive: true signal clicked @@ -49,10 +54,42 @@ Item { anchors.fill: parent color: control.color radius: height * 0.5 + clip: true Behavior on color { ColorAnimation {} } + + + Ripple { + id: ripple + clipRadius: height + clip: true + width: parent.width + height: parent.height + pressed: mouseArea.pressed + anchor: background + active: mouseArea.pressed || mouseArea.visualFocus || mouseArea.containsMouse + color: control.Material.rippleColor + + layer.enabled: true + layer.effect: OpacityMask { + maskSource: Item { + width: ripple.width + height: ripple.height + Rectangle { + anchors.fill: parent + radius: Math.min(width, height) * 0.5 + } + } + } + } + } + + + ColorOverlay { + source: ripple + color: "red" } Text { @@ -75,7 +112,7 @@ Item { MouseArea { id: mouseArea anchors.fill: parent - enabled: control.enabled + enabled: control.enabled && control.interactive onClicked: control.clicked() } } diff --git a/OmobiDisplayApp/ressources/qml/ConnectPage.qml b/OmobiDisplayApp/ressources/qml/ConnectPage.qml index e28c844..17e34a9 100644 --- a/OmobiDisplayApp/ressources/qml/ConnectPage.qml +++ b/OmobiDisplayApp/ressources/qml/ConnectPage.qml @@ -4,6 +4,7 @@ import QtQuick.Layouts 1.0 import de.itsblue.omobidisplayapp 1.0 import de.itsblue.bluetoothleuart 1.0 import QtQuick.Controls.Material 2.0 +import QtGraphicalEffects 1.0 Page { id: root diff --git a/OmobiDisplayApp/ressources/qml/ConnectedPage.qml b/OmobiDisplayApp/ressources/qml/ConnectedPage.qml index 4a98d13..b001671 100644 --- a/OmobiDisplayApp/ressources/qml/ConnectedPage.qml +++ b/OmobiDisplayApp/ressources/qml/ConnectedPage.qml @@ -2,6 +2,7 @@ import QtQuick 2.0 import QtQuick.Controls 2.9 import QtQuick.Layouts 1.0 import QtQuick.Controls.Material 2.0 +import QtGraphicalEffects 1.0 import de.itsblue.omobidisplayapp 1.0 import de.itsblue.bluetoothleuart 1.0 @@ -30,7 +31,28 @@ Page { color: root.Material.foreground - text: "Omobi Display 1" //backend.bleController.currentDevice.name + text: backend.bleController.currentDevice === null ? "":backend.bleController.currentDevice.name + + ToolButton { + id: editButton + anchors { + verticalCenter: parent.verticalCenter + left: parent.right + margins: parent.height * 0.1 + } + + height: parent.height * 0.7 + width: height + + font.styleName: fontAwesome.name + font.pixelSize: height * 0.3 + + flat: true + + text: "\uf044" + + onClicked: displayEditDialog.edit() + } } Text { @@ -65,6 +87,10 @@ Page { } } + DisplayEditDialog { + id: displayEditDialog + } + Dialog { id: loadingDialog diff --git a/OmobiDisplayApp/ressources/qml/DisplayEditDialog.qml b/OmobiDisplayApp/ressources/qml/DisplayEditDialog.qml new file mode 100644 index 0000000..ee26b5a --- /dev/null +++ b/OmobiDisplayApp/ressources/qml/DisplayEditDialog.qml @@ -0,0 +1,91 @@ +import QtQuick 2.12 +import QtQuick.Controls 2.12 +import QtQuick.Layouts 1.9 +import QtQuick.Controls.Material 2.0 + +import de.itsblue.omobidisplayapp 1.0 + +Dialog { + id: control + + parent: Overlay.overlay + + x: (parent.width - width) / 2 + y: (parent.height - height) / 2 + + width: parent.width * 0.9 + + modal: true + + title: qsTr("Edit display settings") + + onAccepted: { + backend.setDisplayCode(codeTextField.value) + backend.setDisplayName(nameTextField.value) + } + + contentItem: ColumnLayout { + id: dataFieldsGridLayout + + width: control.width * 0.9 + + TextInputDelegate { + id: nameTextField + Layout.fillWidth: true + required: true + text: qsTr("Display name\n(needs restart)") + } + + PasswordInputDelegate { + id: codeTextField + Layout.fillWidth: true + required: true + text: qsTr("Display code (4 digits)") + placeholderText: qsTr("Enter new display code") + repeatPlaceholderText: qsTr("Enter new display code again") + } + } + + + footer: DialogButtonBox { + + // alignment: Qt.AlignHCenter + buttonLayout: DialogButtonBox.GnomeLayout + + Material.background: "transparent" + + Button { + flat: true + enabled: nameTextField.value !== "" + text: "save" + DialogButtonBox.buttonRole: DialogButtonBox.AcceptRole + } + + Button { + flat: true + text: "cancel" + DialogButtonBox.buttonRole: DialogButtonBox.RejectRole + } + } + + function edit() { + + reset() + + nameTextField.value = backend.bleController.currentDevice.name + + open() + } + + function add(model) { + editingModel = model + editing = false + reset() + open() + } + + function reset() { + nameTextField.value = "" + codeTextField.value = "" + } +} diff --git a/OmobiDisplayApp/ressources/qml/PasswordInputDelegate.qml b/OmobiDisplayApp/ressources/qml/PasswordInputDelegate.qml new file mode 100644 index 0000000..00326e4 --- /dev/null +++ b/OmobiDisplayApp/ressources/qml/PasswordInputDelegate.qml @@ -0,0 +1,119 @@ +import QtQuick 2.0 +import QtQuick.Controls 2.9 +import QtQuick.Controls.Material 2.0 +import QtQuick.Layouts 1.0 + +ItemDelegate { + id: control + + property string value: "" + property bool required: false + property color textColor: control.required && value === "" ? "red":control.Material.foreground + property string placeholderText: "" + property string repeatPlaceholderText: "" + property int minimumLength: 4 + property int maximumLength: 4 + + onClicked: { + textField.text = value + textEditDialog.open() + } + + Text { + anchors { + right: nextPageIconText.left + verticalCenter: parent.verticalCenter + rightMargin: control.padding + } + + width: parent.width * 0.6 + elide: Text.ElideRight + font.pixelSize: parent.font.pixelSize + + horizontalAlignment: Text.AlignRight + + text: "****" + } + + Text { + id: nextPageIconText + + anchors { + right: parent.right + verticalCenter: parent.verticalCenter + rightMargin: control.padding + } + + font.pixelSize: parent.height * 0.5 + + verticalAlignment: Text.AlignVCenter + + text: ">" + } + + Dialog { + id: textEditDialog + parent: Overlay.overlay + + x: (parent.width - width) / 2 + y: (parent.height - height) / 2 + + width: parent.width * 0.9 + + Material.theme: control.Material.theme + Material.accent: control.Material.accent + modal: true + + title: control.text + + contentItem: ColumnLayout { + TextField { + id: textField + + Layout.fillWidth: true + + placeholderText: control.placeholderText + text: control.value + + color: text.length < 4 || text.length > 4 ? "red":control.Material.foreground + } + + TextField { + id: repeatTextField + + Layout.fillWidth: true + + placeholderText: control.repeatPlaceholderText + text: control.value + + color: repeatTextField.text !== textField.text ? "red":control.Material.foreground + } + } + + + footer: DialogButtonBox { + + // alignment: Qt.AlignHCenter + buttonLayout: DialogButtonBox.GnomeLayout + + Material.background: "transparent" + + Button { + flat: true + enabled: !(textField.text.length < 4 || textField.text.length > 4) && textField.text === repeatTextField.text + text: "save" + DialogButtonBox.buttonRole: DialogButtonBox.AcceptRole + } + + Button { + flat: true + text: "cancel" + DialogButtonBox.buttonRole: DialogButtonBox.RejectRole + } + } + + onAccepted: { + control.value = textField.text + } + } +} diff --git a/OmobiDisplayApp/ressources/qml/TextEditDialog.qml b/OmobiDisplayApp/ressources/qml/TextEditDialog.qml index 9c3359a..58ba22e 100644 --- a/OmobiDisplayApp/ressources/qml/TextEditDialog.qml +++ b/OmobiDisplayApp/ressources/qml/TextEditDialog.qml @@ -62,9 +62,6 @@ Dialog { ColumnLayout { id: dataFieldsGridLayout - property double fontSizeMultiplier: 0.14 - property double labelWidthMultiplier: 0.4 - width: control.width * 0.9 SwitchDelegate { diff --git a/OmobiDisplayApp/ressources/qml/main.qml b/OmobiDisplayApp/ressources/qml/main.qml index 5d62b80..d7e292a 100644 --- a/OmobiDisplayApp/ressources/qml/main.qml +++ b/OmobiDisplayApp/ressources/qml/main.qml @@ -42,6 +42,11 @@ ApplicationWindow { id: backend } + FontLoader { + id: fontAwesome + source: "qrc:/fa5regular.woff" + } + StackView { id: mainStack diff --git a/OmobiDisplayApp/ressources/qml/qml.qrc b/OmobiDisplayApp/ressources/qml/qml.qrc index 0875c94..20565fe 100644 --- a/OmobiDisplayApp/ressources/qml/qml.qrc +++ b/OmobiDisplayApp/ressources/qml/qml.qrc @@ -13,5 +13,7 @@ ColorPickerDelegate.qml ColorPicker.qml Chip.qml + DisplayEditDialog.qml + PasswordInputDelegate.qml diff --git a/OmobiDisplayApp/ressources/shared/fa5regular.woff b/OmobiDisplayApp/ressources/shared/fa5regular.woff new file mode 100644 index 0000000..24de566 Binary files /dev/null and b/OmobiDisplayApp/ressources/shared/fa5regular.woff differ diff --git a/OmobiDisplayApp/ressources/shared/shared.qrc b/OmobiDisplayApp/ressources/shared/shared.qrc index 8be7d48..74f0f89 100644 --- a/OmobiDisplayApp/ressources/shared/shared.qrc +++ b/OmobiDisplayApp/ressources/shared/shared.qrc @@ -2,5 +2,6 @@ omobi.png itsblue.png + fa5regular.woff diff --git a/vscode/OmobiLEDdisplayBluetooth/include/OmobiLedDisplay.h b/vscode/OmobiLEDdisplayBluetooth/include/OmobiLedDisplay.h index 347ce50..8a64a6b 100644 --- a/vscode/OmobiLEDdisplayBluetooth/include/OmobiLedDisplay.h +++ b/vscode/OmobiLEDdisplayBluetooth/include/OmobiLedDisplay.h @@ -33,12 +33,15 @@ private: GetTextSetParameterCommand = 11, GetDisplayBrightnessCommand = 12, SetTextSetParameterCommand = 20, - SetDisplayBrightnessCommand = 21 + SetDisplayBrightnessCommand = 21, + SetDisplayCodeCommand = 22, + SetDisplayNameCommand = 23 }; enum OmobiDisplayStatusCode { Success = 200, + BadRequestError = 400, Unauthorized = 401, InternalError = 500, DisplayControllerError = 501 diff --git a/vscode/OmobiLEDdisplayBluetooth/src/OmobiLedDisplay.cpp b/vscode/OmobiLEDdisplayBluetooth/src/OmobiLedDisplay.cpp index bc85f0b..ad03c03 100644 --- a/vscode/OmobiLEDdisplayBluetooth/src/OmobiLedDisplay.cpp +++ b/vscode/OmobiLEDdisplayBluetooth/src/OmobiLedDisplay.cpp @@ -12,12 +12,13 @@ OmobiLedDisplay::OmobiLedDisplay(String deviceName, Adafruit_NeoMatrix *ledDispl this->ledDisplayController = new LedDisplayController(ledDisplayMatrix); this->ledDisplayController->registerEepromUnit(this->eepromManager); - // init ble server - this->bleServer = new BluetoothLeUartServer("Omobi Display", "92fecb20-1406-426a-afa5-cd5c1f306462", "92fecb21-1406-426a-afa5-cd5c1f306462", "92fecb22-1406-426a-afa5-cd5c1f306462"); - this->bleServer->setCallbacks(this); - + // register eeprom for this class this->eepromUnit = this->eepromManager->registerEempromUnit(sizeof(DisplayProperties)); this->loadProperties(); + + // init ble server + this->bleServer = new BluetoothLeUartServer(this->properties.deviceName, "92fecb20-1406-426a-afa5-cd5c1f306462", "92fecb21-1406-426a-afa5-cd5c1f306462", "92fecb22-1406-426a-afa5-cd5c1f306462"); + this->bleServer->setCallbacks(this); } void OmobiLedDisplay::loop() @@ -170,6 +171,30 @@ void OmobiLedDisplay::onDataReceived(String dataString) replyStatus = Success; break; } + case SetDisplayCodeCommand: { + String code = requestData["displayCode"]; + if(code.length() != 4) { + replyStatus = BadRequestError; + break; + } + + strncpy(this->properties.deviceCode, code.c_str(), sizeof(this->properties.deviceCode)); + this->storeProperties(); + replyStatus = Success; + break; + } + case SetDisplayNameCommand: { + String name = requestData["displayName"]; + if(name.length() <= 0) { + replyStatus = BadRequestError; + break; + } + + strncpy(this->properties.deviceName, name.c_str(), sizeof(this->properties.deviceName)); + this->storeProperties(); + replyStatus = Success; + break; + } default: break; }