Merge PR #193: Improve Kiosk experience

This commit is contained in:
Jenkins 2019-05-22 15:56:07 +02:00
commit 56c4999dfd
27 changed files with 478 additions and 186 deletions

View File

@ -177,8 +177,12 @@ void NymeaConnection::onSslErrors(const QList<QSslError> &errors)
certificateFingerprint.append(digest.mid(i,1).toHex().toUpper());
}
// Ignore self signed certs for connections to localhost
if (QHostAddress(transport->url().host()) == QHostAddress::LocalHost || QHostAddress(transport->url().host()) == QHostAddress::LocalHostIPv6) {
ignoredErrors.append(error);
// Check old style fingerprint storage
if (storedFingerPrint == certificateFingerprint) {
} else if (storedFingerPrint == certificateFingerprint) {
qDebug() << "This fingerprint is known to us.";
ignoredErrors.append(error);

View File

@ -271,6 +271,7 @@ void JsonRpcClient::processCreateUser(const QVariantMap &data)
{
qDebug() << "create user response:" << data;
if (data.value("status").toString() == "success" && data.value("params").toMap().value("error").toString() == "UserErrorNoError") {
emit createUserSucceeded();
m_initialSetupRequired = false;
emit initialSetupRequiredChanged();
} else {

View File

@ -93,6 +93,7 @@ signals:
void invalidProtocolVersion(const QString &actualVersion, const QString &minimumVersion);
void authenticationFailed();
void pushButtonAuthFailed();
void createUserSucceeded();
void createUserFailed(const QString &error);
void cloudConnectionStateChanged();

View File

@ -75,6 +75,8 @@ int main(int argc, char *argv[])
parser.addHelpOption();
QCommandLineOption kioskOption = QCommandLineOption({"k", "kiosk"}, "Start the application in kiosk mode.");
parser.addOption(kioskOption);
QCommandLineOption connectOption = QCommandLineOption({"c", "connect"}, "Connect to nymea:core without discovery.", "host");
parser.addOption(connectOption);
parser.process(application);
// Initialize app log controller as early as possible, but after setting app name etc
@ -124,6 +126,7 @@ int main(int argc, char *argv[])
engine->rootContext()->setContextProperty("styleController", &styleController);
engine->rootContext()->setContextProperty("kioskMode", parser.isSet(kioskOption));
engine->rootContext()->setContextProperty("autoConnectHost", parser.value(connectOption));
engine->rootContext()->setContextProperty("systemProductType", QSysInfo::productType());

View File

@ -17,6 +17,7 @@ linux:!android:LIBS += -lavahi-client -lavahi-common
PRE_TARGETDEPS += ../libnymea-app-core ../libnymea-common
HEADERS += \
platformintegration/generic/raspberrypihelper.h \
stylecontroller.h \
pushnotifications.h \
platformhelper.h \
@ -24,6 +25,7 @@ HEADERS += \
applogcontroller.h
SOURCES += main.cpp \
platformintegration/generic/raspberrypihelper.cpp \
stylecontroller.cpp \
pushnotifications.cpp \
platformhelper.cpp \

View File

@ -4,3 +4,18 @@ PlatformHelper::PlatformHelper(QObject *parent) : QObject(parent)
{
}
bool PlatformHelper::canControlScreen() const
{
return false;
}
int PlatformHelper::screenTimeout() const
{
return 0;
}
void PlatformHelper::setScreenTimeout(int screenTimeout)
{
Q_UNUSED(screenTimeout)
}

View File

@ -12,6 +12,8 @@ class PlatformHelper : public QObject
Q_PROPERTY(QString deviceModel READ deviceModel CONSTANT)
Q_PROPERTY(QString deviceManufacturer READ deviceManufacturer CONSTANT)
Q_PROPERTY(QString machineHostname READ machineHostname CONSTANT)
Q_PROPERTY(bool canControlScreen READ canControlScreen CONSTANT)
Q_PROPERTY(int screenTimeout READ screenTimeout WRITE setScreenTimeout NOTIFY screenTimeoutChanged)
public:
enum HapticsFeedback {
@ -35,10 +37,15 @@ public:
virtual QString deviceModel() const = 0;
virtual QString deviceManufacturer() const = 0;
virtual bool canControlScreen() const;
virtual int screenTimeout() const;
virtual void setScreenTimeout(int screenTimeout);
Q_INVOKABLE virtual void vibrate(HapticsFeedback feedbackType) = 0;
signals:
void permissionsRequestFinished();
void screenTimeoutChanged();
};
#endif // PLATFORMHELPER_H

View File

@ -2,7 +2,7 @@
PlatformHelperGeneric::PlatformHelperGeneric(QObject *parent) : PlatformHelper(parent)
{
m_piHelper = new RaspberryPiHelper(this);
}
void PlatformHelperGeneric::requestPermissions()
@ -49,6 +49,24 @@ QString PlatformHelperGeneric::deviceManufacturer() const
return QSysInfo::productType();
}
bool PlatformHelperGeneric::canControlScreen() const
{
return m_piHelper->active();
}
int PlatformHelperGeneric::screenTimeout() const
{
return m_piHelper->screenTimeout();
}
void PlatformHelperGeneric::setScreenTimeout(int timeout)
{
if (m_piHelper->screenTimeout() != timeout) {
m_piHelper->setScreenTimeout(timeout);
emit screenTimeoutChanged();
}
}
void PlatformHelperGeneric::vibrate(PlatformHelper::HapticsFeedback feedbyckType)
{
Q_UNUSED(feedbyckType)

View File

@ -3,6 +3,7 @@
#include <QObject>
#include "platformhelper.h"
#include "raspberrypihelper.h"
class PlatformHelperGeneric : public PlatformHelper
{
@ -21,10 +22,14 @@ public:
virtual QString deviceModel() const override;
virtual QString deviceManufacturer() const override;
Q_INVOKABLE virtual void vibrate(HapticsFeedback feedbyckType) override;
signals:
virtual bool canControlScreen() const override;
virtual int screenTimeout() const override;
virtual void setScreenTimeout(int timeout) override;
public slots:
Q_INVOKABLE virtual void vibrate(HapticsFeedback feedbyckType) override;
private:
RaspberryPiHelper *m_piHelper = nullptr;
};
#endif // PLATFORMHELPERGENERIC_H

View File

@ -0,0 +1,106 @@
#include "raspberrypihelper.h"
#include <QDebug>
#include <QApplication>
#include <QWindow>
#include <QSettings>
RaspberryPiHelper::RaspberryPiHelper(QObject *parent) : QObject(parent)
{
m_sysFsFile.setFileName("/sys/class/backlight/rpi_backlight/bl_power");
bool available = m_sysFsFile.open(QFile::ReadWrite | QFile::Text);
if (!available) {
return;
}
qDebug() << "Raspberry Pi detected. Enabling backlight control";
screenOn();
foreach (QWindow *w, qApp->topLevelWindows()) {
w->installEventFilter(this);
}
QSettings settings;
m_screenOffTimer.setInterval(settings.value("screenOffTimeout", 15000).toInt());
m_screenOffTimer.setSingleShot(true);
connect(&m_screenOffTimer, &QTimer::timeout, this, &RaspberryPiHelper::screenOff);
if (m_screenOffTimer.interval() > 0) {
m_screenOffTimer.start();
}
}
bool RaspberryPiHelper::active() const
{
return m_sysFsFile.isOpen();
}
int RaspberryPiHelper::screenTimeout() const
{
return m_screenOffTimer.interval();
}
void RaspberryPiHelper::setScreenTimeout(int timeout)
{
m_screenOffTimer.setInterval(timeout);
QSettings settings;
settings.setValue("screenOffTimeout", timeout);
if (timeout > 0) {
m_screenOffTimer.start();
} else {
m_screenOffTimer.stop();
}
}
bool RaspberryPiHelper::eventFilter(QObject *watched, QEvent *event)
{
if (m_screenOffTimer.interval() == 0) {
return QObject::eventFilter(watched, event);
}
QList<QEvent::Type> watchedTypes = {
QEvent::ActivationChange,
QEvent::ApplicationStateChange,
QEvent::KeyPress,
QEvent::KeyRelease,
QEvent::MouseButtonPress,
QEvent::MouseButtonRelease,
QEvent::MouseMove,
QEvent::Show,
QEvent::TouchBegin,
QEvent::TouchEnd,
QEvent::TouchUpdate,
};
if (!watchedTypes.contains(event->type())) {
return QObject::eventFilter(watched, event);
}
if (!m_screenOffTimer.isActive()) {
screenOn();
m_screenOffTimer.start();
return true;
}
m_screenOffTimer.start( );
return QObject::eventFilter(watched, event);
}
void RaspberryPiHelper::screenOn()
{
qDebug() << "Turning screen on";
int ret = m_sysFsFile.write("0\n");
m_sysFsFile.flush();
if (ret < 0) {
qWarning() << "Failed to power on screen";
}
}
void RaspberryPiHelper::screenOff()
{
qDebug() << "Turning screen off";
int ret = m_sysFsFile.write("1\n");
m_sysFsFile.flush();
if (ret < 0) {
qWarning() << "Failed to power off screen";
}
}

View File

@ -0,0 +1,29 @@
#ifndef RASPBERRYPIHELPER_H
#define RASPBERRYPIHELPER_H
#include <QObject>
#include <QTimer>
#include <QFile>
class RaspberryPiHelper : public QObject
{
Q_OBJECT
public:
explicit RaspberryPiHelper(QObject *parent = nullptr);
bool active() const;
int screenTimeout() const;
void setScreenTimeout(int timeout);
bool eventFilter(QObject *watched, QEvent *event) override;
private slots:
void screenOn();
void screenOff();
private:
QTimer m_screenOffTimer;
QFile m_sysFsFile;
};
#endif // RASPBERRYPIHELPER_H

View File

@ -2,7 +2,7 @@
<qresource prefix="/">
<file>ui/Nymea.qml</file>
<file>ui/SettingsPage.qml</file>
<file>ui/LoginPage.qml</file>
<file>ui/connection/LoginPage.qml</file>
<file>ui/MagicPage.qml</file>
<file>ui/PushButtonAuthPage.qml</file>
<file>ui/KeyboardLoader.qml</file>
@ -182,5 +182,6 @@
<file>ui/magic/SelectStatePage.qml</file>
<file>ui/system/SystemUpdatePage.qml</file>
<file>ui/components/UpdateRunningOverlay.qml</file>
<file>ui/connection/SetupWizard.qml</file>
</qresource>
</RCC>

View File

@ -1,24 +1,32 @@
import QtQuick 2.0
import QtQuick 2.4
Item {
id: root
implicitHeight: childrenRect.height
implicitHeight: active ? childrenRect.height : 0
property bool active: d.kbd && d.kbd.active
Behavior on implicitHeight { NumberAnimation { duration: 130; easing.type: Easing.InOutQuad } }
QtObject {
id: d
property var kbd: null
property string virtualKeyboardString:
'
import QtQuick 2.8;
import QtQuick.VirtualKeyboard 2.1
InputPanel {
id: inputPanel
y: Qt.inputMethod.visible ? parent.height - inputPanel.height : parent.height
anchors.left: parent.left
anchors.right: parent.right
}
'
}
property string virtualKeyboardString:
'
import QtQuick 2.8;
import QtQuick.VirtualKeyboard 2.1
InputPanel {
id: inputPanel
y: Qt.inputMethod.visible ? parent.height - inputPanel.height : parent.height
anchors.left: parent.left
anchors.right: parent.right
}
'
Component.onCompleted: {
if (useVirtualKeyboard) {
var kbd = Qt.createQmlObject(virtualKeyboardString, root);
d.kbd = Qt.createQmlObject(d.virtualKeyboardString, root);
}
}
}

View File

@ -1,141 +0,0 @@
import QtQuick 2.5
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.1
import Nymea 1.0
import "components"
Page {
id: root
signal backPressed();
header: GuhHeader {
text: qsTr("Welcome to %1!").arg(app.systemName)
backButtonVisible: true
onBackPressed: root.backPressed()
}
Connections {
target: engine.jsonRpcClient
onAuthenticationFailed: {
var popup = errorDialog.createObject(root)
popup.text = qsTr("Sorry, that wasn't right. Try again please.")
popup.open();
}
onCreateUserFailed: {
print("createUser failed")
var message;
switch (error) {
case "UserErrorInvalidUserId":
message = qsTr("The email you've entered isn't valid.")
break;
case "UserErrorDuplicateUserId":
message = qsTr("The email you've entered is already used.")
break;
case "UserErrorBadPassword":
message = qsTr("The password you've chose is too weak.")
break;
case "UserErrorBackendError":
message = qsTr("An error happened with the user storage. Please make sure your %1 box is installed correctly.")
break;
}
var popup = errorDialog.createObject(root, {text: message});
popup.open();
}
}
ColumnLayout {
anchors.fill: parent
anchors.margins: app.margins
spacing: app.margins
Label {
Layout.fillWidth: true
text: engine.jsonRpcClient.initialSetupRequired ?
qsTr("In order to use your %1 system, please enter your email address and set a password for your nymea box.").arg(app.systemName)
: qsTr("In order to use your %1 system, please log in.").arg(app.systemName)
wrapMode: Text.WordWrap
}
ColumnLayout {
Layout.fillWidth: true
Label {
text: qsTr("Your e-mail address:")
Layout.fillWidth: true
}
TextField {
id: usernameTextField
Layout.fillWidth: true
inputMethodHints: Qt.ImhEmailCharactersOnly
placeholderText: "john.smith@cooldomain.com"
}
}
ColumnLayout {
Layout.fillWidth: true
Label {
Layout.fillWidth: true
text: qsTr("Password:")
}
TextField {
id: passwordTextField
Layout.fillWidth: true
echoMode: TextInput.Password
}
}
ColumnLayout {
Layout.fillWidth: true
visible: engine.jsonRpcClient.initialSetupRequired
Label {
Layout.fillWidth: true
text: qsTr("Confirm password:")
}
TextField {
id: confirmPasswordTextField
Layout.fillWidth: true
echoMode: TextInput.Password
}
}
Label {
Layout.fillWidth: true
visible: engine.jsonRpcClient.initialSetupRequired
opacity: (passwordTextField.text.length > 0 && passwordTextField.text.length < 8) || passwordTextField.text != confirmPasswordTextField.text ? 1 : 0
text: passwordTextField.text.length < 8 ? qsTr("This password isn't long enought to be secure, add some more characters please.")
: qsTr("The passwords don't match.")
wrapMode: Text.WordWrap
Layout.preferredHeight: confirmPasswordTextField.height * 2
color: app.accentColor
}
Button {
Layout.fillWidth: true
text: qsTr("OK")
enabled: usernameTextField.text.length >= 5 && passwordTextField.text.length >= 8
&& (!engine.jsonRpcClient.initialSetupRequired || confirmPasswordTextField.text == passwordTextField.text)
onClicked: {
if (engine.jsonRpcClient.initialSetupRequired) {
print("create user")
engine.jsonRpcClient.createUser(usernameTextField.text, passwordTextField.text);
} else {
print("authenticate", usernameTextField.text, passwordTextField.text, "nymea-app")
engine.jsonRpcClient.authenticate(usernameTextField.text, passwordTextField.text, "nymea-app");
}
}
}
Item {
Layout.fillHeight: true
Layout.fillWidth: true
}
}
Component {
id: errorDialog
ErrorDialog {
}
}
}

View File

@ -168,7 +168,6 @@ Page {
ColorIcon {
height: app.iconSize / 2
width: height
visible: infoPane.connectedState !== null && infoPane.connectedState.value === false
color: "white"
name: "../images/system-update.svg"
RotationAnimation on rotation { from: 0; to: 360; duration: 2000; loops: Animation.Infinite; running: engine.systemController.updateRunning }

View File

@ -54,6 +54,7 @@ ApplicationWindow {
RootItem {
id: rootItem
anchors.fill: parent
anchors.bottomMargin: keyboardRect.height
}
NymeaDiscovery {

View File

@ -33,31 +33,30 @@ Page {
ColumnLayout {
anchors { left: parent.left; right: parent.right; verticalCenter: parent.verticalCenter }
anchors.margins: app.margins
spacing: app.margins
spacing: app.margins * 2
RowLayout {
Label {
Layout.fillWidth: true
spacing: app.margins
horizontalAlignment: Text.AlignHCenter
color: app.accentColor
text: qsTr("Authentication required")
wrapMode: Text.WordWrap
font.pixelSize: app.largeFont
}
ColorIcon {
height: app.iconSize * 2
width: height
color: app.accentColor
name: "../images/info.svg"
}
Label {
color: app.accentColor
text: qsTr("Authentication required")
wrapMode: Text.WordWrap
Layout.fillWidth: true
font.pixelSize: app.largeFont
}
Image {
Layout.preferredWidth: app.iconSize * 6
Layout.preferredHeight: width
source: "images/nymea-box-setup.svg"
Layout.alignment: Qt.AlignHCenter
sourceSize.width: width
sourceSize.height: height
}
Label {
Layout.fillWidth: true
horizontalAlignment: Text.AlignHCenter
text: qsTr("Please press the button on your %1 box to authenticate this device.").arg(app.systemName)
wrapMode: Text.WordWrap
}

View File

@ -105,8 +105,10 @@ Item {
Component.onCompleted: {
setupPushNotifications();
if (tabSettings.lastConnectedHost.length > 0) {
if (autoConnectHost.length > 0) {
var host = discovery.nymeaHosts.createLanHost("Manual connection", autoConnectHost);
engine.connection.connect(host)
} else if (tabSettings.lastConnectedHost.length > 0) {
print("Last connected host was", tabSettings.lastConnectedHost)
var cachedHost = discovery.nymeaHosts.find(tabSettings.lastConnectedHost);
if (cachedHost) {
@ -143,7 +145,17 @@ Item {
})
return;
} else {
var page = pageStack.push(Qt.resolvedUrl("LoginPage.qml"));
if (engine.jsonRpcClient.initialSetupRequired) {
var page = pageStack.push(Qt.resolvedUrl("connection/SetupWizard.qml"));
page.backPressed.connect(function() {
tabSettings.lastConnectedHost = "";
engine.connection.disconnect()
init();
})
return;
}
var page = pageStack.push(Qt.resolvedUrl("connection/LoginPage.qml"));
page.backPressed.connect(function() {
tabSettings.lastConnectedHost = "";
engine.connection.disconnect()

View File

@ -89,6 +89,35 @@ Page {
checked: settings.showConnectionTabs
onClicked: settings.showConnectionTabs = checked
}
CheckDelegate {
id: screenOffCheck
Layout.fillWidth: true
text: qsTr("Turn screen off when idle")
visible: PlatformHelper.canControlScreen
checked: PlatformHelper.screenTimeout > 0
onClicked: PlatformHelper.screenTimeout = (checked ? 15000 : 0)
}
ItemDelegate {
Layout.fillWidth: true
Layout.preferredHeight: screenOffCheck.height
visible: PlatformHelper.screenTimeout > 0
topPadding: 0
contentItem: RowLayout {
Label {
Layout.fillWidth: true
text: qsTr("Screen off timeout")
}
SpinBox {
value: PlatformHelper.screenTimeout / 1000
onValueModified: {
PlatformHelper.screenTimeout = value * 1000
}
}
Label {
text: qsTr("seconds")
}
}
}
}
Component {

View File

@ -12,7 +12,6 @@ Page {
Component.onCompleted: {
print("Ready to connect")
pageStack.push(discoveryPage, StackView.Immediate)
}

View File

@ -0,0 +1,158 @@
import QtQuick 2.5
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.1
import Nymea 1.0
import "../components"
Page {
id: root
signal backPressed();
header: GuhHeader {
text: qsTr("Welcome to %1!").arg(app.systemName)
backButtonVisible: true
onBackPressed: root.backPressed()
}
Connections {
target: engine.jsonRpcClient
onAuthenticationFailed: {
var popup = errorDialog.createObject(root)
popup.text = qsTr("Sorry, that wasn't right. Try again please.")
popup.open();
}
onCreateUserSucceeded: {
engine.jsonRpcClient.authenticate(usernameTextField.text, passwordTextField.text, "nymea-app");
}
onCreateUserFailed: {
print("createUser failed")
var message;
switch (error) {
case "UserErrorInvalidUserId":
message = qsTr("The email you've entered isn't valid.")
break;
case "UserErrorDuplicateUserId":
message = qsTr("The email you've entered is already used.")
break;
case "UserErrorBadPassword":
message = qsTr("The password you've chose is too weak.")
break;
case "UserErrorBackendError":
message = qsTr("An error happened with the user storage. Please make sure your %1 box is installed correctly.")
break;
}
var popup = errorDialog.createObject(root, {text: message});
popup.open();
}
}
Flickable {
anchors.fill: parent
contentHeight: contentColumn.implicitHeight
ColumnLayout {
id: contentColumn
width: parent.width
spacing: app.margins
RowLayout {
Layout.margins: app.margins
spacing: app.margins
ColorIcon {
Layout.preferredHeight: app.iconSize * 2
Layout.preferredWidth: app.iconSize * 2
name: "../images/lock-closed.svg"
color: app.accentColor
}
Label {
Layout.fillWidth: true
text: engine.jsonRpcClient.initialSetupRequired ?
qsTr("In order to use your %1 system, please enter your email address and set a password for your %1 box.").arg(app.systemName)
: qsTr("In order to use your %1 system, please log in.").arg(app.systemName)
wrapMode: Text.WordWrap
}
}
GridLayout {
Layout.fillWidth: true
Layout.leftMargin: app.margins; Layout.rightMargin: app.margins
columns: app.width > 400 ? 2 : 1
Label {
text: qsTr("Your e-mail address:")
Layout.fillWidth: true
}
TextField {
id: usernameTextField
Layout.fillWidth: true
inputMethodHints: Qt.ImhEmailCharactersOnly
placeholderText: "john.smith@cooldomain.com"
}
Label {
Layout.fillWidth: true
text: qsTr("Password:")
}
TextField {
id: passwordTextField
Layout.fillWidth: true
echoMode: TextInput.Password
}
Label {
visible: engine.jsonRpcClient.initialSetupRequired
Layout.fillWidth: true
text: qsTr("Confirm password:")
}
TextField {
id: confirmPasswordTextField
visible: engine.jsonRpcClient.initialSetupRequired
Layout.fillWidth: true
echoMode: TextInput.Password
}
}
Label {
Layout.fillWidth: true
Layout.leftMargin: app.margins; Layout.rightMargin: app.margins
visible: engine.jsonRpcClient.initialSetupRequired
opacity: (passwordTextField.text.length > 0 && passwordTextField.text.length < 8) || passwordTextField.text != confirmPasswordTextField.text ? 1 : 0
text: passwordTextField.text.length < 8 ? qsTr("This password isn't long enought to be secure, add some more characters please.")
: qsTr("The passwords don't match.")
wrapMode: Text.WordWrap
color: app.accentColor
font.pixelSize: app.smallFont
}
Button {
Layout.fillWidth: true
Layout.leftMargin: app.margins; Layout.rightMargin: app.margins; Layout.bottomMargin: app.margins
text: qsTr("OK")
enabled: usernameTextField.text.length >= 5 && passwordTextField.text.length >= 8
&& (!engine.jsonRpcClient.initialSetupRequired || confirmPasswordTextField.text == passwordTextField.text)
onClicked: {
if (engine.jsonRpcClient.initialSetupRequired) {
print("create user")
engine.jsonRpcClient.createUser(usernameTextField.text, passwordTextField.text);
} else {
print("authenticate", usernameTextField.text, passwordTextField.text, "nymea-app")
engine.jsonRpcClient.authenticate(usernameTextField.text, passwordTextField.text, "nymea-app");
}
}
}
}
}
Component {
id: errorDialog
ErrorDialog {
}
}
}

View File

@ -0,0 +1,28 @@
import QtQuick 2.5
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.1
import Nymea 1.0
import "../components"
Page {
id: root
signal backPressed();
header: GuhHeader {
text: qsTr("First setup")
backButtonVisible: true
onBackPressed: root.backPressed()
}
EmptyViewPlaceholder {
anchors.centerIn: parent
width: parent.width - app.margins * 2
title: qsTr("Welcome to %1!").arg(app.systemName)
text: qsTr("This %1 system has not been set up yet. This wizard will guide you through a few simple steps to set it up.").arg(app.systemName)
imageSource: "qrc:/styles/%1/logo.svg".arg(styleController.currentStyle)
buttonText: qsTr("Next")
onButtonClicked: {
var page = pageStack.push(Qt.resolvedUrl("LoginPage.qml"));
}
}
}

View File

@ -1,4 +1,4 @@
[Seat:*]
autologin-user=nymea
user-session=nymea-app-kiosk
xserver-command=X -nocursor

View File

@ -1,2 +1,3 @@
#!/bin/sh
/usr/bin/nymea-app --kiosk
export QT_IM_MODULE=qtvirtualkeyboard
/usr/bin/nymea-app --kiosk --connect nymeas://127.0.0.1:2222

View File

@ -0,0 +1,2 @@
ACTION=="add", SUBSYSTEM=="backlight", RUN+="/bin/chgrp nymea /sys/class/backlight/%k/bl_power"
ACTION=="add", SUBSYSTEM=="backlight", RUN+="/bin/chmod g+w /sys/class/backlight/%k/bl_power"

View File

@ -50,5 +50,9 @@ Section: shells
Multi-Arch: same
Depends: nymea-app,
openbox,
lightdm,
qtvirtualkeyboard-plugin,
qtdeclarative5-folderlistmodel-plugin,
Provides: lightdm-greeter
Description: Run nymea:app in kiosk mode
This package will install nymea:app in kiosk mode on your machine.

View File

@ -1,3 +1,4 @@
packaging/linux-common/nymea-app-kiosk.desktop /usr/share/xsessions/
packaging/linux-common/lightdm/40-nymea-app-kiosk.conf /usr/share/lightdm/lightdm.conf.d/
packaging/linux-common/lightdm/60-nymea-app-kiosk.conf /usr/share/lightdm/lightdm.conf.d/
packaging/linux-common/nymea-app-kiosk-wrapper /usr/bin/
packaging/linux-common/udev/90-pi-backlight.rules /lib/udev/rules.d/