Merge PR #285: Implement new system time api
This commit is contained in:
commit
13343bf04e
@ -32,8 +32,6 @@ void NymeaConfiguration::init()
|
||||
m_webSocketServerConfigurations->clear();
|
||||
m_mqttServerConfigurations->clear();
|
||||
m_client->sendCommand("Configuration.GetConfigurations", this, "getConfigurationsResponse");
|
||||
m_client->sendCommand("Configuration.GetAvailableLanguages", this, "getAvailableLanguagesResponse");
|
||||
m_client->sendCommand("Configuration.GetTimeZones", this, "getTimezonesResponse");
|
||||
m_client->sendCommand("Configuration.GetMqttServerConfigurations", this, "getMqttServerConfigsReply");
|
||||
m_client->sendCommand("Configuration.GetMqttPolicies", this, "getMqttPoliciesReply");
|
||||
}
|
||||
@ -50,38 +48,11 @@ void NymeaConfiguration::setServerName(const QString &serverName)
|
||||
m_client->sendCommand("Configuration.SetServerName", params, this, "setServerNameResponse");
|
||||
}
|
||||
|
||||
QString NymeaConfiguration::language() const
|
||||
{
|
||||
return m_language;
|
||||
}
|
||||
|
||||
void NymeaConfiguration::setLanguage(const QString &language)
|
||||
{
|
||||
QVariantMap params;
|
||||
params.insert("language", language);
|
||||
m_client->sendCommand("Configuration.SetLanguage", params);
|
||||
}
|
||||
|
||||
QStringList NymeaConfiguration::availableLanguages() const
|
||||
{
|
||||
return m_availableLanguages;
|
||||
}
|
||||
|
||||
QString NymeaConfiguration::timezone() const
|
||||
{
|
||||
return m_timezone;
|
||||
}
|
||||
|
||||
void NymeaConfiguration::setTimezone(const QString &timezone)
|
||||
{
|
||||
QVariantMap params;
|
||||
params.insert("timeZone", timezone);
|
||||
m_client->sendCommand("Configuration.SetTimeZone", params, this, "setTimezoneResponse");
|
||||
}
|
||||
|
||||
QStringList NymeaConfiguration::timezones() const
|
||||
{
|
||||
return m_timezones;
|
||||
m_client->sendCommand("System.SetTimeZone", params, this, "setTimezoneResponse");
|
||||
}
|
||||
|
||||
bool NymeaConfiguration::debugServerEnabled() const
|
||||
@ -259,10 +230,6 @@ void NymeaConfiguration::getConfigurationsResponse(const QVariantMap ¶ms)
|
||||
emit debugServerEnabledChanged();
|
||||
m_serverName = basicConfig.value("serverName").toString();
|
||||
emit serverNameChanged();
|
||||
m_language = basicConfig.value("language").toString();
|
||||
emit languageChanged();
|
||||
m_timezone = basicConfig.value("timeZone").toString();
|
||||
emit timezoneChanged();
|
||||
QVariantMap cloudConfig = params.value("params").toMap().value("cloud").toMap();
|
||||
m_cloudEnabled = cloudConfig.value("enabled").toBool();
|
||||
emit cloudEnabledChanged();
|
||||
@ -290,25 +257,6 @@ void NymeaConfiguration::getConfigurationsResponse(const QVariantMap ¶ms)
|
||||
}
|
||||
}
|
||||
|
||||
void NymeaConfiguration::getAvailableLanguagesResponse(const QVariantMap ¶ms)
|
||||
{
|
||||
// qDebug() << "available languages" << params;
|
||||
m_availableLanguages = params.value("params").toMap().value("languages").toStringList();
|
||||
emit availableLanguagesChanged();
|
||||
}
|
||||
|
||||
void NymeaConfiguration::getTimezonesResponse(const QVariantMap ¶ms)
|
||||
{
|
||||
// qDebug() << "Get timezones response" << params;
|
||||
m_timezones = params.value("params").toMap().value("timeZones").toStringList();
|
||||
emit timezonesChanged();
|
||||
}
|
||||
|
||||
void NymeaConfiguration::setTimezoneResponse(const QVariantMap ¶ms)
|
||||
{
|
||||
qDebug() << "Set timezones response" << params;
|
||||
}
|
||||
|
||||
void NymeaConfiguration::setServerNameResponse(const QVariantMap ¶ms)
|
||||
{
|
||||
qDebug() << "Server name set:" << params;
|
||||
@ -416,10 +364,6 @@ void NymeaConfiguration::notificationReceived(const QVariantMap ¬ification)
|
||||
emit debugServerEnabledChanged();
|
||||
m_serverName = params.value("serverName").toString();
|
||||
emit serverNameChanged();
|
||||
m_language = params.value("language").toString();
|
||||
emit languageChanged();
|
||||
m_timezone = params.value("timeZone").toString();
|
||||
emit timezoneChanged();
|
||||
return;
|
||||
}
|
||||
if (notif == "Configuration.CloudConfigurationChanged") {
|
||||
|
||||
@ -19,12 +19,6 @@ class NymeaConfiguration : public JsonHandler
|
||||
|
||||
Q_PROPERTY(QString serverName READ serverName WRITE setServerName NOTIFY serverNameChanged)
|
||||
|
||||
Q_PROPERTY(QString language READ language WRITE setLanguage NOTIFY languageChanged)
|
||||
Q_PROPERTY(QStringList availableLanguages READ availableLanguages NOTIFY availableLanguagesChanged)
|
||||
|
||||
Q_PROPERTY(QString timezone READ timezone WRITE setTimezone NOTIFY timezoneChanged)
|
||||
Q_PROPERTY(QStringList timezones READ timezones NOTIFY timezonesChanged)
|
||||
|
||||
Q_PROPERTY(bool cloudEnabled READ cloudEnabled WRITE setCloudEnabled NOTIFY cloudEnabledChanged)
|
||||
Q_PROPERTY(bool debugServerEnabled READ debugServerEnabled WRITE setDebugServerEnabled NOTIFY debugServerEnabledChanged)
|
||||
|
||||
@ -87,9 +81,6 @@ private:
|
||||
Q_INVOKABLE void setDebugServerEnabledResponse(const QVariantMap ¶ms);
|
||||
Q_INVOKABLE void setServerNameResponse(const QVariantMap ¶ms);
|
||||
Q_INVOKABLE void setCloudEnabledResponse(const QVariantMap ¶ms);
|
||||
Q_INVOKABLE void getAvailableLanguagesResponse(const QVariantMap ¶ms);
|
||||
Q_INVOKABLE void getTimezonesResponse(const QVariantMap ¶ms);
|
||||
Q_INVOKABLE void setTimezoneResponse(const QVariantMap ¶ms);
|
||||
Q_INVOKABLE void setTcpConfigReply(const QVariantMap ¶ms);
|
||||
Q_INVOKABLE void deleteTcpConfigReply(const QVariantMap ¶ms);
|
||||
Q_INVOKABLE void setWebSocketConfigReply(const QVariantMap ¶ms);
|
||||
@ -108,10 +99,6 @@ private:
|
||||
signals:
|
||||
void debugServerEnabledChanged();
|
||||
void serverNameChanged();
|
||||
void languageChanged();
|
||||
void availableLanguagesChanged();
|
||||
void timezoneChanged();
|
||||
void timezonesChanged();
|
||||
void cloudEnabledChanged();
|
||||
|
||||
private:
|
||||
@ -119,10 +106,6 @@ private:
|
||||
|
||||
bool m_debugServerEnabled = false;
|
||||
QString m_serverName;
|
||||
QString m_language;
|
||||
QStringList m_availableLanguages;
|
||||
QString m_timezone;
|
||||
QStringList m_timezones;
|
||||
bool m_cloudEnabled = false;
|
||||
|
||||
ServerConfigurations *m_tcpServerConfigurations = nullptr;
|
||||
|
||||
@ -5,6 +5,8 @@
|
||||
#include "types/packages.h"
|
||||
#include "types/repositories.h"
|
||||
|
||||
#include <QTimeZone>
|
||||
|
||||
SystemController::SystemController(JsonRpcClient *jsonRpcClient, QObject *parent):
|
||||
JsonHandler(parent),
|
||||
m_jsonRpcClient(jsonRpcClient)
|
||||
@ -12,6 +14,8 @@ SystemController::SystemController(JsonRpcClient *jsonRpcClient, QObject *parent
|
||||
m_jsonRpcClient->registerNotificationHandler(this, "notificationReceived");
|
||||
m_packages = new Packages(this);
|
||||
m_repositories = new Repositories(this);
|
||||
|
||||
startTimer(1000, Qt::VeryCoarseTimer);
|
||||
}
|
||||
|
||||
void SystemController::init()
|
||||
@ -22,6 +26,8 @@ void SystemController::init()
|
||||
m_jsonRpcClient->sendCommand("System.GetCapabilities", this, "getCapabilitiesResponse");
|
||||
} else {
|
||||
m_powerManagementAvailable = false;
|
||||
m_updateManagementAvailable = false;
|
||||
m_timeManagementAvailable = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -101,6 +107,63 @@ int SystemController::enableRepository(const QString &id, bool enabled)
|
||||
return m_jsonRpcClient->sendCommand("System.EnableRepository", params, this, "enableRepositoryResponse");
|
||||
}
|
||||
|
||||
bool SystemController::timeManagementAvailable() const
|
||||
{
|
||||
return m_timeManagementAvailable;
|
||||
}
|
||||
|
||||
QDateTime SystemController::serverTime() const
|
||||
{
|
||||
return m_serverTime;
|
||||
}
|
||||
|
||||
void SystemController::setServerTime(const QDateTime &serverTime)
|
||||
{
|
||||
QVariantMap params;
|
||||
params.insert("automaticTime", false);
|
||||
params.insert("time", serverTime.toSecsSinceEpoch());
|
||||
params.insert("timeZone", serverTime.timeZone().id());
|
||||
m_jsonRpcClient->sendCommand("System.SetTime", params, this, "setTimeResponse");
|
||||
}
|
||||
|
||||
QStringList SystemController::timeZones() const
|
||||
{
|
||||
QStringList ret;
|
||||
foreach (const QByteArray &tzId, QTimeZone::availableTimeZoneIds()) {
|
||||
ret << tzId;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
QString SystemController::serverTimeZone() const
|
||||
{
|
||||
return m_serverTime.timeZone().id();
|
||||
}
|
||||
|
||||
void SystemController::setServerTimeZone(const QString &serverTimeZone)
|
||||
{
|
||||
QVariantMap params;
|
||||
params.insert("timeZone", serverTimeZone);
|
||||
m_jsonRpcClient->sendCommand("System.SetTime", params, this, "setTimeResponse");
|
||||
}
|
||||
|
||||
bool SystemController::automaticTimeAvailable() const
|
||||
{
|
||||
return m_automaticTimeAvailable;
|
||||
}
|
||||
|
||||
bool SystemController::automaticTime() const
|
||||
{
|
||||
return m_automaticTime;
|
||||
}
|
||||
|
||||
void SystemController::setAutomaticTime(bool automaticTime)
|
||||
{
|
||||
QVariantMap params;
|
||||
params.insert("automaticTime", automaticTime);
|
||||
m_jsonRpcClient->sendCommand("System.SetTime", params, this, "setTimeResponse");
|
||||
}
|
||||
|
||||
void SystemController::getCapabilitiesResponse(const QVariantMap &data)
|
||||
{
|
||||
qDebug() << "capabilities received" << data;
|
||||
@ -110,11 +173,18 @@ void SystemController::getCapabilitiesResponse(const QVariantMap &data)
|
||||
m_updateManagementAvailable = data.value("params").toMap().value("updateManagement").toBool();
|
||||
emit updateManagementAvailableChanged();
|
||||
|
||||
m_timeManagementAvailable = data.value("params").toMap().value("timeManagement").toBool();
|
||||
emit timeManagementAvailableChanged();
|
||||
|
||||
if (m_updateManagementAvailable) {
|
||||
m_jsonRpcClient->sendCommand("System.GetUpdateStatus", this, "getUpdateStatusResponse");
|
||||
m_jsonRpcClient->sendCommand("System.GetPackages", this, "getPackagesResponse");
|
||||
m_jsonRpcClient->sendCommand("System.GetRepositories", this, "getRepositoriesResponse");
|
||||
}
|
||||
|
||||
// if (m_jsonRpcClient->ensureServerVersion("4.1")) {
|
||||
m_jsonRpcClient->sendCommand("System.GetTime", this, "getServerTimeResponse");
|
||||
// }
|
||||
}
|
||||
|
||||
void SystemController::getUpdateStatusResponse(const QVariantMap &data)
|
||||
@ -164,6 +234,24 @@ void SystemController::enableRepositoryResponse(const QVariantMap ¶ms)
|
||||
emit enableRepositoryFinished(params.value("id").toInt(), params.value("params").toMap().value("success").toBool());
|
||||
}
|
||||
|
||||
void SystemController::getServerTimeResponse(const QVariantMap ¶ms)
|
||||
{
|
||||
qDebug() << "Server time" << params;
|
||||
m_serverTime = QDateTime::fromSecsSinceEpoch(params.value("params").toMap().value("time").toUInt());
|
||||
m_serverTime.setTimeZone(QTimeZone(params.value("params").toMap().value("timeZone").toString().toUtf8()));
|
||||
emit serverTimeChanged();
|
||||
emit serverTimeZoneChanged();
|
||||
m_automaticTimeAvailable = params.value("params").toMap().value("automaticTimeAvailable").toBool();
|
||||
emit automaticTimeAvailableChanged();
|
||||
m_automaticTime = params.value("params").toMap().value("automaticTime").toBool();
|
||||
emit automaticTimeChanged();
|
||||
}
|
||||
|
||||
void SystemController::setTimeResponse(const QVariantMap ¶ms)
|
||||
{
|
||||
qDebug() << "set time response" << params;
|
||||
}
|
||||
|
||||
void SystemController::notificationReceived(const QVariantMap &data)
|
||||
{
|
||||
QString notification = data.value("notification").toString();
|
||||
@ -233,7 +321,24 @@ void SystemController::notificationReceived(const QVariantMap &data)
|
||||
qWarning() << "System capabilites changed: power management:" << m_powerManagementAvailable << "update management:" << m_updateManagementAvailable;
|
||||
emit powerManagementAvailableChanged();
|
||||
emit updateManagementAvailableChanged();
|
||||
} else if (notification == "System.TimeConfigurationChanged") {
|
||||
qDebug() << "System time configuration changed";
|
||||
m_serverTime = QDateTime::fromSecsSinceEpoch(data.value("params").toMap().value("time").toUInt());
|
||||
m_serverTime.setTimeZone(QTimeZone(data.value("params").toMap().value("timeZone").toByteArray()));
|
||||
emit serverTimeChanged();
|
||||
emit serverTimeZoneChanged();
|
||||
m_automaticTimeAvailable = data.value("params").toMap().value("automaticTimeAvailable").toBool();
|
||||
emit automaticTimeAvailableChanged();
|
||||
m_automaticTime = data.value("params").toMap().value("automaticTime").toBool();
|
||||
emit automaticTimeChanged();
|
||||
} else {
|
||||
qWarning() << "Unhandled System Notification" << data.value("notification");
|
||||
}
|
||||
}
|
||||
|
||||
void SystemController::timerEvent(QTimerEvent *event)
|
||||
{
|
||||
Q_UNUSED(event)
|
||||
m_serverTime = m_serverTime.addSecs(1);
|
||||
emit serverTimeChanged();
|
||||
}
|
||||
|
||||
@ -14,12 +14,19 @@ class SystemController : public JsonHandler
|
||||
Q_PROPERTY(bool powerManagementAvailable READ powerManagementAvailable NOTIFY powerManagementAvailableChanged)
|
||||
// Whether the update mechanism is available in the connected core
|
||||
Q_PROPERTY(bool updateManagementAvailable READ updateManagementAvailable NOTIFY updateManagementAvailableChanged)
|
||||
Q_PROPERTY(bool timeManagementAvailable READ timeManagementAvailable NOTIFY timeManagementAvailableChanged)
|
||||
|
||||
Q_PROPERTY(bool updateManagementBusy READ updateManagementBusy NOTIFY updateManagementBusyChanged)
|
||||
Q_PROPERTY(bool updateRunning READ updateRunning NOTIFY updateRunningChanged)
|
||||
Q_PROPERTY(Packages* packages READ packages CONSTANT)
|
||||
Q_PROPERTY(Repositories* repositories READ repositories CONSTANT)
|
||||
|
||||
Q_PROPERTY(QDateTime serverTime READ serverTime WRITE setServerTime NOTIFY serverTimeChanged)
|
||||
Q_PROPERTY(QString serverTimeZone READ serverTimeZone WRITE setServerTimeZone NOTIFY serverTimeZoneChanged)
|
||||
Q_PROPERTY(QStringList timeZones READ timeZones CONSTANT)
|
||||
Q_PROPERTY(bool automaticTimeAvailable READ automaticTimeAvailable NOTIFY automaticTimeAvailableChanged)
|
||||
Q_PROPERTY(bool automaticTime READ automaticTime WRITE setAutomaticTime NOTIFY automaticTimeChanged)
|
||||
|
||||
public:
|
||||
explicit SystemController(JsonRpcClient *jsonRpcClient, QObject *parent = nullptr);
|
||||
|
||||
@ -27,29 +34,40 @@ public:
|
||||
QString nameSpace() const override;
|
||||
|
||||
bool powerManagementAvailable() const;
|
||||
bool updateManagementAvailable() const;
|
||||
|
||||
Q_INVOKABLE void reboot();
|
||||
Q_INVOKABLE void shutdown();
|
||||
|
||||
bool updateManagementAvailable() const;
|
||||
bool updateManagementBusy() const;
|
||||
bool updateRunning() const;
|
||||
|
||||
Q_INVOKABLE void checkForUpdates();
|
||||
Packages* packages() const;
|
||||
Q_INVOKABLE void updatePackages(const QString packageId = QString());
|
||||
Q_INVOKABLE void removePackages(const QString packageId = QString());
|
||||
|
||||
Repositories* repositories() const;
|
||||
Q_INVOKABLE int enableRepository(const QString &id, bool enabled);
|
||||
|
||||
bool timeManagementAvailable() const;
|
||||
QDateTime serverTime() const;
|
||||
void setServerTime(const QDateTime &serverTime);
|
||||
QStringList timeZones() const;
|
||||
QString serverTimeZone() const;
|
||||
void setServerTimeZone(const QString &serverTimeZone);
|
||||
bool automaticTimeAvailable() const;
|
||||
bool automaticTime() const;
|
||||
void setAutomaticTime(bool automaticTime);
|
||||
|
||||
signals:
|
||||
void powerManagementAvailableChanged();
|
||||
void updateManagementAvailableChanged();
|
||||
void timeManagementAvailableChanged();
|
||||
void updateManagementBusyChanged();
|
||||
void updateRunningChanged();
|
||||
void enableRepositoryFinished(int id, bool success);
|
||||
void serverTimeChanged();
|
||||
void serverTimeZoneChanged();
|
||||
void automaticTimeAvailableChanged();
|
||||
void automaticTimeChanged();
|
||||
|
||||
private slots:
|
||||
void getCapabilitiesResponse(const QVariantMap &data);
|
||||
@ -58,19 +76,31 @@ private slots:
|
||||
void getRepositoriesResponse(const QVariantMap &data);
|
||||
void removePackageResponse(const QVariantMap ¶ms);
|
||||
void enableRepositoryResponse(const QVariantMap ¶ms);
|
||||
void getServerTimeResponse(const QVariantMap ¶ms);
|
||||
void setTimeResponse(const QVariantMap ¶ms);
|
||||
|
||||
void notificationReceived(const QVariantMap &data);
|
||||
|
||||
|
||||
protected:
|
||||
void timerEvent(QTimerEvent *event) override;
|
||||
|
||||
private:
|
||||
JsonRpcClient *m_jsonRpcClient = nullptr;
|
||||
|
||||
bool m_powerManagementAvailable = false;
|
||||
bool m_updateManagementAvailable = false;
|
||||
bool m_timeManagementAvailable = false;
|
||||
|
||||
bool m_updateManagementBusy = false;
|
||||
bool m_updateRunning = false;
|
||||
Packages *m_packages = nullptr;
|
||||
Repositories *m_repositories = nullptr;
|
||||
|
||||
QDateTime m_serverTime;
|
||||
QStringList m_timeZones;
|
||||
bool m_automaticTimeAvailable = false;
|
||||
bool m_automaticTime = false;
|
||||
};
|
||||
|
||||
#endif // SYSTEMCONTROLLER_H
|
||||
|
||||
@ -80,7 +80,7 @@ void PlatformHelperAndroid::vibrate(PlatformHelper::HapticsFeedback feedbackType
|
||||
int duration;
|
||||
switch (feedbackType) {
|
||||
case HapticsFeedbackSelection:
|
||||
duration = 20;
|
||||
duration = 10;
|
||||
break;
|
||||
case HapticsFeedbackImpact:
|
||||
duration = 30;
|
||||
|
||||
@ -201,5 +201,7 @@
|
||||
<file>ui/mainviews/GroupsView.qml</file>
|
||||
<file>ui/grouping/GroupPage.qml</file>
|
||||
<file>ui/delegates/ThingTile.qml</file>
|
||||
<file>ui/components/TimePicker.qml</file>
|
||||
<file>ui/components/DatePicker.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
||||
134
nymea-app/ui/components/DatePicker.qml
Normal file
134
nymea-app/ui/components/DatePicker.qml
Normal file
@ -0,0 +1,134 @@
|
||||
import QtQuick 2.3
|
||||
import QtQuick.Controls 2.1
|
||||
import QtQuick.Layouts 1.2
|
||||
import Nymea 1.0
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
|
||||
property date date
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
ColorIcon {
|
||||
Layout.preferredHeight: app.iconSize
|
||||
Layout.preferredWidth: app.iconSize
|
||||
name: "../images/back.svg"
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
var newDate = new Date(root.date)
|
||||
newDate.setMonth(root.date.getMonth() - 1)
|
||||
root.date = newDate
|
||||
}
|
||||
}
|
||||
}
|
||||
Label {
|
||||
text: root.date.toLocaleDateString()
|
||||
Layout.fillWidth: true
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
ColorIcon {
|
||||
Layout.preferredHeight: app.iconSize
|
||||
Layout.preferredWidth: app.iconSize
|
||||
name: "../images/next.svg"
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
var newDate = new Date(root.date)
|
||||
newDate.setMonth(root.date.getMonth() + 1)
|
||||
root.date = newDate
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ThinDivider {}
|
||||
|
||||
ListModel {
|
||||
id: monthModel
|
||||
ListElement { text: qsTr("January"); days: 31; leapYearDays: 31 }
|
||||
ListElement { text: qsTr("February"); days: 28; leapYearDays: 29 }
|
||||
ListElement { text: qsTr("March"); days: 31; leapYearDays: 31 }
|
||||
ListElement { text: qsTr("April"); days: 30; leapYearDays: 30 }
|
||||
ListElement { text: qsTr("May"); days: 31; leapYearDays: 31 }
|
||||
ListElement { text: qsTr("June"); days: 30; leapYearDays: 30 }
|
||||
ListElement { text: qsTr("July"); days: 31; leapYearDays: 31 }
|
||||
ListElement { text: qsTr("August"); days: 31; leapYearDays: 31 }
|
||||
ListElement { text: qsTr("September"); days: 30; leapYearDays: 30 }
|
||||
ListElement { text: qsTr("October"); days: 31; leapYearDays: 31 }
|
||||
ListElement { text: qsTr("November"); days: 30; leapYearDays: 30 }
|
||||
ListElement { text: qsTr("December"); days: 31; leapYearDays: 31 }
|
||||
}
|
||||
|
||||
ListModel {
|
||||
id: weekModel
|
||||
ListElement { text: qsTr("Mon") }
|
||||
ListElement { text: qsTr("Tue") }
|
||||
ListElement { text: qsTr("Wed") }
|
||||
ListElement { text: qsTr("Thu") }
|
||||
ListElement { text: qsTr("Fri") }
|
||||
ListElement { text: qsTr("Sat") }
|
||||
ListElement { text: qsTr("Sun") }
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Repeater {
|
||||
model: weekModel
|
||||
Item {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: width
|
||||
Label {
|
||||
anchors.centerIn: parent
|
||||
text: model.text
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GridLayout {
|
||||
id: daysGrid
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
columns: 7
|
||||
columnSpacing: 0
|
||||
rowSpacing: 0
|
||||
|
||||
property date firstOfMonth: new Date(root.date.getFullYear(), root.date.getMonth(), 1)
|
||||
property int offset: ((firstOfMonth.getDay() - 1) % 7 + 7) % 7
|
||||
property bool isLeapYear: firstOfMonth.getFullYear() % 4 == 0 && firstOfMonth.getFullYear() % 100 != 0
|
||||
property int daysInMonth: isLeapYear ? monthModel.get(root.date.getMonth()).leapYearDays : monthModel.get(root.date.getMonth()).days
|
||||
property int daysInPreviousMonth: isLeapYear ? monthModel.get((root.date.getMonth() + 11) % 12).leapYearDays : monthModel.get((root.date.getMonth() + 11) % 12).days
|
||||
|
||||
Repeater {
|
||||
model: 6 * 7
|
||||
|
||||
delegate: Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: width
|
||||
radius: width / 2
|
||||
property int dayOfMonth: index - daysGrid.offset + 1
|
||||
property bool isPreviousMonth: dayOfMonth < 1
|
||||
property bool isNextMonth: dayOfMonth > daysGrid.daysInMonth
|
||||
property int correctedDayOfMonth: isPreviousMonth ? daysGrid.daysInPreviousMonth + dayOfMonth
|
||||
: isNextMonth ? dayOfMonth - daysGrid.daysInMonth : dayOfMonth
|
||||
color: !isPreviousMonth && !isNextMonth && correctedDayOfMonth == root.date.getDate() ? app.accentColor : "transparent"
|
||||
Label {
|
||||
anchors.centerIn: parent
|
||||
opacity: isPreviousMonth || isNextMonth ? 0.6 : 1
|
||||
|
||||
text: correctedDayOfMonth
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
var newDate = new Date(root.date)
|
||||
newDate.setDate(dayOfMonth)
|
||||
root.date = newDate
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
261
nymea-app/ui/components/TimePicker.qml
Normal file
261
nymea-app/ui/components/TimePicker.qml
Normal file
@ -0,0 +1,261 @@
|
||||
import QtQuick 2.3
|
||||
import QtQuick.Controls 2.1
|
||||
import QtQuick.Layouts 1.2
|
||||
import Nymea 1.0
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
spacing: app.margins
|
||||
|
||||
property int hour: 0
|
||||
property int minute: 0
|
||||
|
||||
function selectHours() {
|
||||
d.mode = "hours"
|
||||
}
|
||||
function selectMinutes() {
|
||||
d.mode = "minutes"
|
||||
}
|
||||
Component.onCompleted: {
|
||||
initTimer.start();
|
||||
}
|
||||
Timer {
|
||||
id: initTimer
|
||||
interval: 1
|
||||
onTriggered: selectHours();
|
||||
}
|
||||
|
||||
Row {
|
||||
Layout.alignment: Qt.AlignHCenter
|
||||
Label {
|
||||
text: app.pad(root.hour, 2)
|
||||
font.pixelSize: app.largeFont * 2
|
||||
opacity: d.mode == "hours" ? 1 : .6
|
||||
Behavior on opacity { NumberAnimation {duration: 250 } }
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: selectHours()
|
||||
}
|
||||
}
|
||||
Label {
|
||||
text: ":"
|
||||
font.pixelSize: app.largeFont * 2
|
||||
}
|
||||
Label {
|
||||
text: app.pad(root.minute, 2)
|
||||
font.pixelSize: app.largeFont * 2
|
||||
opacity: d.mode == "minutes" ? 1 : .6
|
||||
Behavior on opacity { NumberAnimation {duration: 250 } }
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: selectMinutes()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: d
|
||||
Layout.fillHeight: true
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: width
|
||||
|
||||
property string mode: "none"
|
||||
|
||||
Item {
|
||||
id: dial
|
||||
height: Math.min(parent.height, parent.width)
|
||||
width: height
|
||||
anchors.centerIn: parent
|
||||
|
||||
Repeater {
|
||||
id: hours12
|
||||
|
||||
model: 12
|
||||
delegate: Item {
|
||||
id: delegate
|
||||
visible: d.mode == "hours"
|
||||
anchors.centerIn: parent
|
||||
height: parent.height
|
||||
rotation: (360 / 12) * (index + 1)
|
||||
width: 30
|
||||
|
||||
property alias field: fieldItem
|
||||
Item {
|
||||
id: fieldItem
|
||||
anchors { left: parent.left; top: parent.top; right: parent.right }
|
||||
height: width
|
||||
|
||||
Label {
|
||||
anchors.centerIn: parent
|
||||
text: index + 1
|
||||
rotation: -delegate.rotation
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Repeater {
|
||||
id: hours24
|
||||
|
||||
property int selectedIndex: root.hour - 12
|
||||
|
||||
model: 12
|
||||
delegate: Item {
|
||||
id: delegate
|
||||
visible: d.mode == "hours"
|
||||
anchors.centerIn: parent
|
||||
height: parent.height - 80
|
||||
rotation: (360 / 12) * (index + 12)
|
||||
width: 30
|
||||
|
||||
property alias field: fieldItem
|
||||
Item {
|
||||
id: fieldItem
|
||||
anchors { left: parent.left; top: parent.top; right: parent.right }
|
||||
height: width
|
||||
|
||||
Label {
|
||||
anchors.centerIn: parent
|
||||
text: index + 12 == 12 ? "00" : index + 12
|
||||
rotation: -delegate.rotation
|
||||
opacity: .8
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Repeater {
|
||||
id: minutes
|
||||
|
||||
property int selectedIndex: 0
|
||||
readonly property int selectedMinute: selectedIndex
|
||||
|
||||
model: 60
|
||||
delegate: Item {
|
||||
id: delegate
|
||||
visible: d.mode == "minutes"
|
||||
anchors.centerIn: parent
|
||||
height: parent.height
|
||||
rotation: (360 / 60) * (index)
|
||||
width: 30
|
||||
|
||||
property alias field: fieldItem
|
||||
Item {
|
||||
id: fieldItem
|
||||
anchors { left: parent.left; top: parent.top; right: parent.right }
|
||||
height: width
|
||||
|
||||
Label {
|
||||
anchors.centerIn: parent
|
||||
text: index
|
||||
rotation: -delegate.rotation
|
||||
visible: index % 5 == 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: newDot
|
||||
height: (parent.height + 10) - (d.mode == "hours" && (root.hour == 0 || root.hour > 12) ? 80 : 0)
|
||||
width: 40
|
||||
anchors.centerIn: parent
|
||||
z: -1
|
||||
rotation: {
|
||||
if (d.mode == "hours") {
|
||||
if (root.hour > 0 && root.hour < 13) {
|
||||
return root.hour * 360 / 12
|
||||
}
|
||||
return (root.hour - 12 % 12) * 360 / 12
|
||||
}
|
||||
return root.minute * 360 / 60
|
||||
}
|
||||
Behavior on height { NumberAnimation { duration: 100 } }
|
||||
Behavior on rotation { RotationAnimation { duration: 100; direction: RotationAnimation.Shortest } }
|
||||
|
||||
Rectangle {
|
||||
anchors { left: parent.left; top: parent.top; right: parent.right }
|
||||
height: width
|
||||
color: app.accentColor
|
||||
radius: width / 2
|
||||
}
|
||||
Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
width: 5
|
||||
height: parent.height / 2
|
||||
color: app.accentColor
|
||||
radius: width / 2
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
|
||||
onPressed: {
|
||||
update();
|
||||
}
|
||||
onPositionChanged: update();
|
||||
onReleased: {
|
||||
if (d.mode == "hours") {
|
||||
selectMinutes();
|
||||
}
|
||||
}
|
||||
|
||||
function update() {
|
||||
var angle = calculateAngle(mouseX, mouseY);
|
||||
|
||||
var items = d.mode == "hours" ? 12 : 60
|
||||
|
||||
// angle : 360 = num : 12
|
||||
var selected = Math.round(angle * items / 360) % items;
|
||||
|
||||
if (d.mode == "hours") {
|
||||
if (calculateDistanceToCenter(mouseX, mouseY) < (width / 2) - 40) {
|
||||
selected = selected + 12
|
||||
}
|
||||
// swap 12 and 00
|
||||
if (selected === 12) {
|
||||
selected = 0
|
||||
} else if (selected === 0) {
|
||||
selected = 12
|
||||
}
|
||||
if (root.hour !== selected) {
|
||||
root.hour = selected
|
||||
PlatformHelper.vibrate(PlatformHelper.HapticsFeedbackSelection)
|
||||
}
|
||||
} else {
|
||||
if (root.minute !== selected) {
|
||||
root.minute = selected
|
||||
PlatformHelper.vibrate(PlatformHelper.HapticsFeedbackSelection)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function calculateAngle(mouseX, mouseY) {
|
||||
// transform coords to center of dial
|
||||
mouseX -= width / 2
|
||||
mouseY -= height / 2
|
||||
|
||||
var rad = Math.atan(mouseY / mouseX);
|
||||
var angle = rad * 180 / Math.PI
|
||||
|
||||
angle += 90;
|
||||
|
||||
if (mouseX < 0 && mouseY >= 0) angle = 180 + angle;
|
||||
if (mouseX < 0 && mouseY < 0) angle = 180 + angle;
|
||||
|
||||
return angle;
|
||||
}
|
||||
|
||||
function calculateDistanceToCenter(mouseX, mouseY) {
|
||||
var a = mouseY - (height / 2)
|
||||
var b = mouseX - (width / 2)
|
||||
var c = Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2))
|
||||
return c;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -8,20 +8,18 @@ import "../components"
|
||||
Page {
|
||||
id: root
|
||||
header: NymeaHeader {
|
||||
text: qsTr("Box settings")
|
||||
text: qsTr("General settings")
|
||||
backButtonVisible: true
|
||||
onBackPressed: pageStack.pop()
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: settingsColumn
|
||||
anchors { left: parent.left; right: parent.right; top: parent.top }
|
||||
id: settingsGrid
|
||||
anchors { horizontalCenter: parent.horizontalCenter; top: parent.top; margins: app.margins }
|
||||
width: Math.min(500, parent.width - app.margins * 2)
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: app.margins
|
||||
Layout.leftMargin: app.margins
|
||||
Layout.rightMargin: app.margins
|
||||
spacing: app.margins
|
||||
Label {
|
||||
text: qsTr("Name")
|
||||
@ -40,63 +38,119 @@ Page {
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: app.margins
|
||||
Layout.rightMargin: app.margins
|
||||
spacing: app.margins
|
||||
|
||||
visible: engine.jsonRpcClient.ensureServerVersion("4.1") && engine.systemController.automaticTimeAvailable
|
||||
Label {
|
||||
text: qsTr("Set date and time automatically")
|
||||
Layout.fillWidth: true
|
||||
text: qsTr("Language")
|
||||
}
|
||||
ComboBox {
|
||||
id: languageBox
|
||||
Layout.fillWidth: true
|
||||
model: engine.nymeaConfiguration.availableLanguages
|
||||
currentIndex: model.indexOf(engine.nymeaConfiguration.language)
|
||||
contentItem: Label {
|
||||
leftPadding: app.margins / 2
|
||||
text: Qt.locale(languageBox.displayText).nativeLanguageName + " (" + Qt.locale(languageBox.displayText).nativeCountryName + ")"
|
||||
elide: Text.ElideRight
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
delegate: ItemDelegate {
|
||||
width: languageBox.width
|
||||
contentItem: Label {
|
||||
text: Qt.locale(modelData).nativeLanguageName + " (" + Qt.locale(modelData).nativeCountryName + ")"
|
||||
elide: Text.ElideRight
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
highlighted: languageBox.highlightedIndex === index
|
||||
}
|
||||
onActivated: {
|
||||
engine.nymeaConfiguration.language = currentText;
|
||||
CheckBox {
|
||||
checked: engine.systemController.automaticTime
|
||||
onClicked: {
|
||||
engine.systemController.automaticTime = checked
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: app.margins
|
||||
Layout.rightMargin: app.margins
|
||||
spacing: app.margins
|
||||
Layout.preferredHeight: dateButton.implicitHeight
|
||||
visible: engine.jsonRpcClient.ensureServerVersion("4.1")
|
||||
Label {
|
||||
text: qsTr("Date")
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
Label {
|
||||
text: engine.systemController.serverTime.toLocaleDateString()
|
||||
Layout.fillWidth: true
|
||||
horizontalAlignment: Text.AlignRight
|
||||
}
|
||||
Button {
|
||||
id: dateButton
|
||||
visible: !engine.systemController.automaticTime && engine.systemController.timeManagementAvailable
|
||||
contentItem: Item {
|
||||
ColorIcon {
|
||||
name: "../images/edit.svg"
|
||||
color: app.foregroundColor
|
||||
anchors.centerIn: parent
|
||||
height: parent.height
|
||||
width: height
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
var popup = datePickerComponent.createObject(root, {dateTime: engine.systemController.serverTime})
|
||||
popup.accepted.connect(function() {
|
||||
print("setting new date", popup.dateTime)
|
||||
engine.systemController.serverTime = popup.dateTime
|
||||
})
|
||||
popup.open();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: app.margins
|
||||
Layout.preferredHeight: timeButton.implicitHeight
|
||||
visible: engine.jsonRpcClient.ensureServerVersion("4.1")
|
||||
Label {
|
||||
text: qsTr("Time")
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
Label {
|
||||
text: engine.systemController.serverTime.toLocaleTimeString(/*Locale.ShortTimeString*/)
|
||||
Layout.fillWidth: true
|
||||
horizontalAlignment: Text.AlignRight
|
||||
}
|
||||
Button {
|
||||
id: timeButton
|
||||
visible: !engine.systemController.automaticTime && engine.systemController.timeManagementAvailable
|
||||
contentItem: Item {
|
||||
ColorIcon {
|
||||
name: "../images/edit.svg"
|
||||
color: app.foregroundColor
|
||||
anchors.centerIn: parent
|
||||
height: parent.height
|
||||
width: height
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
var popup = timePickerComponent.createObject(root, {hour: engine.systemController.serverTime.getHours(), minute: engine.systemController.serverTime.getMinutes()})
|
||||
popup.accepted.connect(function() {
|
||||
var date = new Date(engine.systemController.serverTime)
|
||||
date.setHours(popup.hour);
|
||||
date.setMinutes(popup.minute)
|
||||
engine.systemController.serverTime = date;
|
||||
})
|
||||
popup.open();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: app.margins
|
||||
visible: engine.jsonRpcClient.ensureServerVersion("4.1")
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
text: qsTr("Time zone")
|
||||
}
|
||||
ComboBox {
|
||||
Layout.minimumWidth: 200
|
||||
model: engine.nymeaConfiguration.timezones
|
||||
currentIndex: model.indexOf(engine.nymeaConfiguration.timezone)
|
||||
model: engine.systemController.timeZones
|
||||
currentIndex: model.indexOf(engine.systemController.serverTimeZone)
|
||||
onActivated: {
|
||||
engine.nymeaConfiguration.timezone = currentText;
|
||||
engine.systemController.serverTimeZone = currentText;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: app.margins
|
||||
text: qsTr("Reboot %1:core").arg(app.systemName)
|
||||
visible: engine.systemController.powerManagementAvailable
|
||||
onClicked: {
|
||||
@ -117,7 +171,6 @@ Page {
|
||||
}
|
||||
Button {
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: app.margins
|
||||
text: qsTr("Shutdown %1:core").arg(app.systemName)
|
||||
visible: engine.systemController.powerManagementAvailable
|
||||
onClicked: {
|
||||
@ -137,4 +190,48 @@ Page {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: timePickerComponent
|
||||
Dialog {
|
||||
id: timePicker
|
||||
property int maxSize: Math.min(parent.width, parent.height)
|
||||
property int size: Math.min(maxSize, 500)
|
||||
property alias hour: p.hour
|
||||
property alias minute: p.minute
|
||||
width: size - 80
|
||||
height: size
|
||||
x: (parent.width - width) / 2
|
||||
y: (parent.height - height) / 2
|
||||
|
||||
TimePicker {
|
||||
id: p
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
}
|
||||
standardButtons: Dialog.Ok | Dialog.Cancel
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: datePickerComponent
|
||||
Dialog {
|
||||
id: datePicker
|
||||
property int maxSize: Math.min(parent.width, parent.height)
|
||||
property int size: Math.min(maxSize, 500)
|
||||
property alias dateTime: p.date
|
||||
width: size - 80
|
||||
height: size
|
||||
x: (parent.width - width) / 2
|
||||
y: (parent.height - height) / 2
|
||||
|
||||
DatePicker {
|
||||
id: p
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
date: datePicker.dateTime
|
||||
}
|
||||
standardButtons: Dialog.Ok | Dialog.Cancel
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user