add support for time based rules and rework rule dialog
This commit is contained in:
parent
3566977f18
commit
6fa3604f52
@ -34,6 +34,12 @@
|
||||
#include "types/stateevaluator.h"
|
||||
#include "types/stateevaluators.h"
|
||||
#include "types/statedescriptor.h"
|
||||
#include "types/timeeventitem.h"
|
||||
#include "types/timeeventitems.h"
|
||||
#include "types/timedescriptor.h"
|
||||
#include "types/repeatingoption.h"
|
||||
#include "types/calendaritems.h"
|
||||
#include "types/calendaritem.h"
|
||||
|
||||
#include <QMetaEnum>
|
||||
|
||||
@ -245,6 +251,10 @@ QVariantMap JsonTypes::packRule(Rule *rule)
|
||||
ret.insert("eventDescriptors", packEventDescriptors(rule->eventDescriptors()));
|
||||
}
|
||||
|
||||
if (rule->timeDescriptor()->timeEventItems()->rowCount() > 0 || rule->timeDescriptor()->calendarItems()->rowCount() > 0) {
|
||||
ret.insert("timeDescriptor", packTimeDescriptor(rule->timeDescriptor()));
|
||||
}
|
||||
|
||||
if (rule->stateEvaluator()) {
|
||||
ret.insert("stateEvaluator", packStateEvaluator(rule->stateEvaluator()));
|
||||
}
|
||||
@ -338,6 +348,67 @@ QVariantMap JsonTypes::packStateEvaluator(StateEvaluator *stateEvaluator)
|
||||
return ret;
|
||||
}
|
||||
|
||||
QVariantMap JsonTypes::packTimeDescriptor(TimeDescriptor *timeDescriptor)
|
||||
{
|
||||
QVariantMap ret;
|
||||
QVariantList timeEventItems;
|
||||
for (int i = 0; i < timeDescriptor->timeEventItems()->rowCount(); i++) {
|
||||
timeEventItems.append(packTimeEventItem(timeDescriptor->timeEventItems()->get(i)));
|
||||
}
|
||||
if (!timeEventItems.isEmpty()) {
|
||||
ret.insert("timeEventItems", timeEventItems);
|
||||
}
|
||||
QVariantList calendarItems;
|
||||
for (int i = 0; i < timeDescriptor->calendarItems()->rowCount(); i++) {
|
||||
calendarItems.append(packCalendarItem(timeDescriptor->calendarItems()->get(i)));
|
||||
}
|
||||
if (!calendarItems.isEmpty()) {
|
||||
ret.insert("calendarItems", calendarItems);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
QVariantMap JsonTypes::packTimeEventItem(TimeEventItem *timeEventItem)
|
||||
{
|
||||
QVariantMap ret;
|
||||
if (!timeEventItem->time().isNull()) {
|
||||
ret.insert("time", timeEventItem->time().toString("hh:mm"));
|
||||
}
|
||||
if (!timeEventItem->dateTime().isNull()) {
|
||||
ret.insert("dateTime", timeEventItem->dateTime().toSecsSinceEpoch());
|
||||
}
|
||||
ret.insert("repeating", packRepeatingOption(timeEventItem->repeatingOption()));
|
||||
return ret;
|
||||
}
|
||||
|
||||
QVariantMap JsonTypes::packCalendarItem(CalendarItem *calendarItem)
|
||||
{
|
||||
QVariantMap ret;
|
||||
ret.insert("duration", calendarItem->duration());
|
||||
if (!calendarItem->dateTime().isNull()) {
|
||||
ret.insert("datetime", calendarItem->dateTime().toSecsSinceEpoch());
|
||||
}
|
||||
if (!calendarItem->startTime().isNull()) {
|
||||
ret.insert("startTime", calendarItem->startTime().toString("hh:mm"));
|
||||
}
|
||||
ret.insert("repeating", packRepeatingOption(calendarItem->repeatingOption()));
|
||||
return ret;
|
||||
}
|
||||
|
||||
QVariantMap JsonTypes::packRepeatingOption(RepeatingOption *repeatingOption)
|
||||
{
|
||||
QVariantMap ret;
|
||||
QMetaEnum repeatingModeEnum = QMetaEnum::fromType<RepeatingOption::RepeatingMode>();
|
||||
ret.insert("mode", repeatingModeEnum.valueToKey(repeatingOption->repeatingMode()));
|
||||
if (!repeatingOption->weekDays().isEmpty()) {
|
||||
ret.insert("weekDays", repeatingOption->weekDays());
|
||||
}
|
||||
if (!repeatingOption->monthDays().isEmpty()) {
|
||||
ret.insert("monthDays", repeatingOption->monthDays());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
DeviceClass::SetupMethod JsonTypes::stringToSetupMethod(const QString &setupMethodString)
|
||||
{
|
||||
if (setupMethodString == "SetupMethodJustAdd") {
|
||||
|
||||
@ -43,6 +43,10 @@ class Rule;
|
||||
class StateEvaluator;
|
||||
class RuleActions;
|
||||
class EventDescriptors;
|
||||
class TimeDescriptor;
|
||||
class TimeEventItem;
|
||||
class CalendarItem;
|
||||
class RepeatingOption;
|
||||
|
||||
class JsonTypes : public QObject
|
||||
{
|
||||
@ -65,6 +69,11 @@ public:
|
||||
static QVariantList packEventDescriptors(EventDescriptors* eventDescriptors);
|
||||
static QVariantMap packParam(Param *param);
|
||||
static QVariantMap packStateEvaluator(StateEvaluator* stateEvaluator);
|
||||
static QVariantMap packTimeDescriptor(TimeDescriptor* timeDescriptor);
|
||||
static QVariantMap packTimeEventItem(TimeEventItem* timeEventItem);
|
||||
static QVariantMap packCalendarItem(CalendarItem* calendarItem);
|
||||
static QVariantMap packRepeatingOption(RepeatingOption* repeatingOption);
|
||||
|
||||
private:
|
||||
static DeviceClass::SetupMethod stringToSetupMethod(const QString &setupMethodString);
|
||||
static QList<DeviceClass::BasicTag> stringListToBasicTags(const QStringList &basicTagsStringList);
|
||||
|
||||
@ -18,6 +18,12 @@
|
||||
#include "types/ruleactionparam.h"
|
||||
#include "types/eventdescriptors.h"
|
||||
#include "types/eventdescriptor.h"
|
||||
#include "types/timedescriptor.h"
|
||||
#include "types/timeeventitems.h"
|
||||
#include "types/timeeventitem.h"
|
||||
#include "types/repeatingoption.h"
|
||||
#include "types/calendaritems.h"
|
||||
#include "types/calendaritem.h"
|
||||
#include "types/rule.h"
|
||||
#include "types/interfaces.h"
|
||||
#include "types/interface.h"
|
||||
@ -104,6 +110,12 @@ void registerQmlTypes() {
|
||||
qmlRegisterUncreatableType<StateDescriptor>(uri, 1, 0, "StateDescriptor", "Uncreatable");
|
||||
qmlRegisterUncreatableType<StateEvaluator>(uri, 1, 0, "StateEvaluator", "Uncreatable");
|
||||
qmlRegisterUncreatableType<StateEvaluators>(uri, 1, 0, "StateEvaluators", "Uncreatable");
|
||||
qmlRegisterUncreatableType<TimeDescriptor>(uri, 1, 0, "TimeDescriptor", "Uncreatable");
|
||||
qmlRegisterUncreatableType<TimeEventItems>(uri, 1, 0, "TimeEventItems", "Uncreatable");
|
||||
qmlRegisterUncreatableType<TimeEventItem>(uri, 1, 0, "TimeEventItem", "Uncreatable");
|
||||
qmlRegisterUncreatableType<RepeatingOption>(uri, 1, 0, "RepeatingOption", "Uncreatable");
|
||||
qmlRegisterUncreatableType<CalendarItems>(uri, 1, 0, "CalendarItems", "Uncreatable");
|
||||
qmlRegisterUncreatableType<CalendarItem>(uri, 1, 0, "CalendarItem", "Uncreatable");
|
||||
|
||||
qmlRegisterUncreatableType<Interface>(uri, 1, 0, "Interface", "Uncreatable");
|
||||
qmlRegisterSingletonType<Interfaces>(uri, 1, 0, "Interfaces", interfacesModel_provider);
|
||||
|
||||
@ -12,7 +12,12 @@
|
||||
#include "types/stateevaluator.h"
|
||||
#include "types/stateevaluators.h"
|
||||
#include "types/statedescriptor.h"
|
||||
#include "types/timedescriptor.h"
|
||||
#include "types/timeeventitems.h"
|
||||
#include "types/timeeventitem.h"
|
||||
#include "types/repeatingoption.h"
|
||||
#include "types/calendaritems.h"
|
||||
#include "types/calendaritem.h"
|
||||
|
||||
#include <QMetaEnum>
|
||||
|
||||
@ -179,6 +184,7 @@ Rule *RuleManager::parseRule(const QVariantMap &ruleMap)
|
||||
parseEventDescriptors(ruleMap.value("eventDescriptors").toList(), rule);
|
||||
parseRuleActions(ruleMap.value("actions").toList(), rule);
|
||||
parseRuleExitActions(ruleMap.value("exitActions").toList(), rule);
|
||||
parseTimeDescriptor(ruleMap.value("timeDescriptor").toMap(), rule);
|
||||
rule->setStateEvaluator(parseStateEvaluator(ruleMap.value("stateEvaluator").toMap()));
|
||||
return rule;
|
||||
}
|
||||
@ -259,12 +265,36 @@ void RuleManager::parseRuleExitActions(const QVariantList &ruleActions, Rule *ru
|
||||
|
||||
void RuleManager::parseTimeDescriptor(const QVariantMap &timeDescriptor, Rule *rule)
|
||||
{
|
||||
Q_UNUSED(rule)
|
||||
Q_UNUSED(timeDescriptor)
|
||||
// foreach (const QVariant &timeEventItemVariant, timeDescriptor.value("timeEventItems").toList()) {
|
||||
// TimeEventItem *timeEventItem = new TimeEventItem();
|
||||
// timeEventItem->setDateTime(QDateTime::fromSecsSinceEpoch(timeEventItemVariant.toMap().value("datetime").toULongLong()));
|
||||
// timeEventItem->setTime(QTime::fromString(timeEventItemVariant.toMap().value("time").toString()));
|
||||
// timeEventItem->setRepeatingOption();
|
||||
// }
|
||||
foreach (const QVariant &timeEventItemVariant, timeDescriptor.value("timeEventItems").toList()) {
|
||||
TimeEventItem *timeEventItem = new TimeEventItem();
|
||||
if (timeEventItemVariant.toMap().contains("datetime")) {
|
||||
timeEventItem->setDateTime(QDateTime::fromSecsSinceEpoch(timeEventItemVariant.toMap().value("datetime").toULongLong()));
|
||||
}
|
||||
if (timeEventItemVariant.toMap().contains("time")){
|
||||
timeEventItem->setTime(QTime::fromString(timeEventItemVariant.toMap().value("time").toString()));
|
||||
}
|
||||
QVariantMap repeatingOptionMap = timeEventItemVariant.toMap().value("repeating").toMap();
|
||||
QMetaEnum modeEnum = QMetaEnum::fromType<RepeatingOption::RepeatingMode>();
|
||||
timeEventItem->repeatingOption()->setRepeatingMode((RepeatingOption::RepeatingMode)modeEnum.keyToValue(repeatingOptionMap.value("mode").toByteArray()));
|
||||
timeEventItem->repeatingOption()->setWeekDays(repeatingOptionMap.value("weekDays").toList());
|
||||
timeEventItem->repeatingOption()->setMonthDays(repeatingOptionMap.value("monthDays").toList());
|
||||
rule->timeDescriptor()->timeEventItems()->addTimeEventItem(timeEventItem);
|
||||
}
|
||||
foreach (const QVariant &calendarItemVariant, timeDescriptor.value("calendarItems").toList()) {
|
||||
CalendarItem *calendarItem = new CalendarItem();
|
||||
if (calendarItemVariant.toMap().contains("datetime")) {
|
||||
calendarItem->setDateTime(QDateTime::fromSecsSinceEpoch(calendarItemVariant.toMap().value("datetime").toULongLong()));
|
||||
}
|
||||
if (calendarItemVariant.toMap().contains("startTime")) {
|
||||
calendarItem->setStartTime(QTime::fromString(calendarItemVariant.toMap().value("startTime").toString()));
|
||||
}
|
||||
calendarItem->setDuration(calendarItemVariant.toMap().value("duration").toInt());
|
||||
QVariantMap repeatingOptionMap = calendarItemVariant.toMap().value("repeating").toMap();
|
||||
QMetaEnum modeEnum = QMetaEnum::fromType<RepeatingOption::RepeatingMode>();
|
||||
calendarItem->repeatingOption()->setRepeatingMode((RepeatingOption::RepeatingMode)modeEnum.keyToValue(repeatingOptionMap.value("mode").toByteArray()));
|
||||
calendarItem->repeatingOption()->setWeekDays(repeatingOptionMap.value("weekDays").toList());
|
||||
calendarItem->repeatingOption()->setMonthDays(repeatingOptionMap.value("monthDays").toList());
|
||||
rule->timeDescriptor()->calendarItems()->addCalendarItem(calendarItem);
|
||||
}
|
||||
// rule->timeDescriptor()
|
||||
}
|
||||
|
||||
@ -51,7 +51,8 @@ HEADERS += \
|
||||
types/timeeventitem.h \
|
||||
types/calendaritem.h \
|
||||
types/timeeventitems.h \
|
||||
types/calendaritems.h
|
||||
types/calendaritems.h \
|
||||
types/repeatingoption.h
|
||||
|
||||
SOURCES += \
|
||||
types/vendor.cpp \
|
||||
@ -93,7 +94,8 @@ SOURCES += \
|
||||
types/timeeventitem.cpp \
|
||||
types/calendaritem.cpp \
|
||||
types/timeeventitems.cpp \
|
||||
types/calendaritems.cpp
|
||||
types/calendaritems.cpp \
|
||||
types/repeatingoption.cpp
|
||||
|
||||
# install header file with relative subdirectory
|
||||
for(header, HEADERS) {
|
||||
|
||||
@ -1,6 +1,62 @@
|
||||
#include "calendaritem.h"
|
||||
|
||||
#include "repeatingoption.h"
|
||||
|
||||
CalendarItem::CalendarItem(QObject *parent) : QObject(parent)
|
||||
{
|
||||
|
||||
m_repeatingOption = new RepeatingOption(this);
|
||||
}
|
||||
|
||||
int CalendarItem::duration() const
|
||||
{
|
||||
return m_duration;
|
||||
}
|
||||
|
||||
void CalendarItem::setDuration(int duration)
|
||||
{
|
||||
if (m_duration != duration) {
|
||||
m_duration = duration;
|
||||
emit durationChanged();
|
||||
}
|
||||
}
|
||||
|
||||
QDateTime CalendarItem::dateTime() const
|
||||
{
|
||||
return m_dateTime;
|
||||
}
|
||||
|
||||
void CalendarItem::setDateTime(const QDateTime &dateTime)
|
||||
{
|
||||
if (m_dateTime != dateTime) {
|
||||
m_dateTime = dateTime;
|
||||
emit dateTimeChanged();
|
||||
}
|
||||
}
|
||||
|
||||
QTime CalendarItem::startTime() const
|
||||
{
|
||||
return m_startTime;
|
||||
}
|
||||
|
||||
void CalendarItem::setStartTime(const QTime &startTime)
|
||||
{
|
||||
if (m_startTime != startTime) {
|
||||
m_startTime = startTime;
|
||||
emit startTimeChanged();
|
||||
}
|
||||
}
|
||||
|
||||
RepeatingOption *CalendarItem::repeatingOption() const
|
||||
{
|
||||
return m_repeatingOption;
|
||||
}
|
||||
|
||||
CalendarItem *CalendarItem::clone() const
|
||||
{
|
||||
CalendarItem* ret = new CalendarItem();
|
||||
ret->m_dateTime = this->m_dateTime;
|
||||
ret->m_duration = this->m_duration;
|
||||
ret->m_repeatingOption = this->m_repeatingOption;
|
||||
ret->m_startTime = this->m_startTime;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -2,16 +2,44 @@
|
||||
#define CALENDARITEM_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QDateTime>
|
||||
|
||||
class RepeatingOption;
|
||||
|
||||
class CalendarItem : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int duration READ duration WRITE setDuration NOTIFY durationChanged)
|
||||
Q_PROPERTY(QDateTime dateTime READ dateTime WRITE setDateTime NOTIFY dateTimeChanged)
|
||||
Q_PROPERTY(QTime startTime READ startTime WRITE setStartTime NOTIFY startTimeChanged)
|
||||
Q_PROPERTY(RepeatingOption* repeatingOption READ repeatingOption CONSTANT)
|
||||
|
||||
public:
|
||||
explicit CalendarItem(QObject *parent = nullptr);
|
||||
|
||||
signals:
|
||||
int duration() const;
|
||||
void setDuration(int duration);
|
||||
|
||||
public slots:
|
||||
QDateTime dateTime() const;
|
||||
void setDateTime(const QDateTime &dateTime);
|
||||
|
||||
QTime startTime() const;
|
||||
void setStartTime(const QTime &startTime);
|
||||
|
||||
RepeatingOption* repeatingOption() const;
|
||||
|
||||
CalendarItem* clone() const;
|
||||
|
||||
signals:
|
||||
void durationChanged();
|
||||
void dateTimeChanged();
|
||||
void startTimeChanged();
|
||||
|
||||
private:
|
||||
int m_duration = 0;
|
||||
QDateTime m_dateTime;
|
||||
QTime m_startTime;
|
||||
RepeatingOption* m_repeatingOption = nullptr;
|
||||
};
|
||||
|
||||
#endif // CALENDARITEM_H
|
||||
#endif // CALENDARITEM_H
|
||||
|
||||
@ -1,6 +1,50 @@
|
||||
#include "calendaritems.h"
|
||||
#include "calendaritem.h"
|
||||
|
||||
CalendarItems::CalendarItems(QObject *parent) : QObject(parent)
|
||||
CalendarItems::CalendarItems(QObject *parent) : QAbstractListModel(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int CalendarItems::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent)
|
||||
return m_list.count();
|
||||
}
|
||||
|
||||
QVariant CalendarItems::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
void CalendarItems::addCalendarItem(CalendarItem *calendarItem)
|
||||
{
|
||||
calendarItem->setParent(this);
|
||||
beginInsertRows(QModelIndex(), m_list.count(), m_list.count());
|
||||
m_list.append(calendarItem);
|
||||
endInsertRows();
|
||||
emit countChanged();
|
||||
}
|
||||
|
||||
void CalendarItems::removeCalendarItem(int index)
|
||||
{
|
||||
if (index < 0 || index > m_list.count()) {
|
||||
return;
|
||||
}
|
||||
beginRemoveRows(QModelIndex(), index, index);
|
||||
m_list.takeAt(index)->deleteLater();
|
||||
endRemoveRows();
|
||||
}
|
||||
|
||||
CalendarItem *CalendarItems::createNewCalendarItem() const
|
||||
{
|
||||
return new CalendarItem();
|
||||
}
|
||||
|
||||
CalendarItem *CalendarItems::get(int index) const
|
||||
{
|
||||
if (index < 0 || index > m_list.count()) {
|
||||
return nullptr;
|
||||
}
|
||||
return m_list.at(index);
|
||||
}
|
||||
|
||||
@ -1,17 +1,31 @@
|
||||
#ifndef CALENDARITEMS_H
|
||||
#define CALENDARITEMS_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QAbstractListModel>
|
||||
|
||||
class CalendarItems : public QObject
|
||||
class CalendarItem;
|
||||
|
||||
class CalendarItems : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int count READ rowCount NOTIFY countChanged)
|
||||
public:
|
||||
explicit CalendarItems(QObject *parent = nullptr);
|
||||
|
||||
signals:
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
|
||||
public slots:
|
||||
Q_INVOKABLE void addCalendarItem(CalendarItem* calendarItem);
|
||||
Q_INVOKABLE void removeCalendarItem(int index);
|
||||
|
||||
Q_INVOKABLE CalendarItem* createNewCalendarItem() const;
|
||||
Q_INVOKABLE CalendarItem* get(int index) const;
|
||||
|
||||
signals:
|
||||
void countChanged();
|
||||
|
||||
private:
|
||||
QList<CalendarItem*> m_list;
|
||||
};
|
||||
|
||||
#endif // CALENDARITEMS_H
|
||||
#endif // CALENDARITEMS_H
|
||||
|
||||
45
libnymea-common/types/repeatingoption.cpp
Normal file
45
libnymea-common/types/repeatingoption.cpp
Normal file
@ -0,0 +1,45 @@
|
||||
#include "repeatingoption.h"
|
||||
|
||||
RepeatingOption::RepeatingOption(QObject *parent) : QObject(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
RepeatingOption::RepeatingMode RepeatingOption::repeatingMode() const
|
||||
{
|
||||
return m_repeatingMode;
|
||||
}
|
||||
|
||||
void RepeatingOption::setRepeatingMode(RepeatingOption::RepeatingMode repeatingMode)
|
||||
{
|
||||
if (m_repeatingMode != repeatingMode) {
|
||||
m_repeatingMode = repeatingMode;
|
||||
emit repeatingModeChanged();
|
||||
}
|
||||
}
|
||||
|
||||
QVariantList RepeatingOption::weekDays() const
|
||||
{
|
||||
return m_weekDays;
|
||||
}
|
||||
|
||||
void RepeatingOption::setWeekDays(const QVariantList &weekDays)
|
||||
{
|
||||
if (m_weekDays != weekDays) {
|
||||
m_weekDays = weekDays;
|
||||
emit weekDaysChanged();
|
||||
}
|
||||
}
|
||||
|
||||
QVariantList RepeatingOption::monthDays() const
|
||||
{
|
||||
return m_monthDays;
|
||||
}
|
||||
|
||||
void RepeatingOption::setMonthDays(const QVariantList &monthDays)
|
||||
{
|
||||
if (m_monthDays != monthDays) {
|
||||
m_monthDays = monthDays;
|
||||
emit monthDaysChanged();
|
||||
}
|
||||
}
|
||||
48
libnymea-common/types/repeatingoption.h
Normal file
48
libnymea-common/types/repeatingoption.h
Normal file
@ -0,0 +1,48 @@
|
||||
#ifndef REPEATINGOPTION_H
|
||||
#define REPEATINGOPTION_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QVariantList>
|
||||
|
||||
class RepeatingOption: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(RepeatingMode repeatingMode READ repeatingMode WRITE setRepeatingMode NOTIFY repeatingModeChanged)
|
||||
Q_PROPERTY(QVariantList weekDays READ weekDays WRITE setWeekDays NOTIFY weekDaysChanged)
|
||||
Q_PROPERTY(QVariantList monthDays READ monthDays WRITE setMonthDays NOTIFY monthDaysChanged)
|
||||
|
||||
public:
|
||||
enum RepeatingMode {
|
||||
RepeatingModeNone,
|
||||
RepeatingModeHourly,
|
||||
RepeatingModeDaily,
|
||||
RepeatingModeWeekly,
|
||||
RepeatingModeMonthly,
|
||||
RepeatingModeYearly
|
||||
};
|
||||
Q_ENUM(RepeatingMode)
|
||||
|
||||
explicit RepeatingOption(QObject *parent = nullptr);
|
||||
|
||||
RepeatingMode repeatingMode() const;
|
||||
void setRepeatingMode(RepeatingMode repeatingMode);
|
||||
|
||||
QVariantList weekDays() const;
|
||||
void setWeekDays(const QVariantList &weekDays);
|
||||
|
||||
QVariantList monthDays() const;
|
||||
void setMonthDays(const QVariantList &monthDays);
|
||||
|
||||
signals:
|
||||
void repeatingModeChanged();
|
||||
void weekDaysChanged();
|
||||
void monthDaysChanged();
|
||||
|
||||
private:
|
||||
RepeatingMode m_repeatingMode = RepeatingModeDaily;
|
||||
QVariantList m_weekDays;
|
||||
QVariantList m_monthDays;
|
||||
};
|
||||
|
||||
|
||||
#endif // REPEATINGOPTION_H
|
||||
@ -4,9 +4,16 @@
|
||||
#include "eventdescriptors.h"
|
||||
#include "stateevaluator.h"
|
||||
#include "stateevaluators.h"
|
||||
#include "statedescriptor.h"
|
||||
#include "ruleaction.h"
|
||||
#include "ruleactions.h"
|
||||
#include "timedescriptor.h"
|
||||
#include "timeeventitems.h"
|
||||
#include "timeeventitem.h"
|
||||
#include "calendaritems.h"
|
||||
#include "calendaritem.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
Rule::Rule(const QUuid &id, QObject *parent) :
|
||||
QObject(parent),
|
||||
@ -14,9 +21,15 @@ Rule::Rule(const QUuid &id, QObject *parent) :
|
||||
m_eventDescriptors(new EventDescriptors(this)),
|
||||
// m_stateEvaluator(new StateEvaluator(this)),
|
||||
m_actions(new RuleActions(this)),
|
||||
m_exitActions(new RuleActions(this))
|
||||
m_exitActions(new RuleActions(this)),
|
||||
m_timeDescriptor(new TimeDescriptor(this))
|
||||
{
|
||||
qDebug() << "### Creating rule" << this;
|
||||
}
|
||||
|
||||
Rule::~Rule()
|
||||
{
|
||||
qDebug() << "### Destroying rule" << this;
|
||||
}
|
||||
|
||||
QUuid Rule::id() const
|
||||
@ -113,11 +126,15 @@ Rule *Rule::clone() const
|
||||
for (int i = 0; i < this->eventDescriptors()->rowCount(); i++) {
|
||||
ret->eventDescriptors()->addEventDescriptor(this->eventDescriptors()->get(i)->clone());
|
||||
}
|
||||
// ret->stateEvaluator()->setStateDescriptor(this->stateEvaluator()->stateDescriptor()->clone());
|
||||
// ret->stateEvaluator()->setStateOperator(this->stateEvaluator()->stateOperator());
|
||||
// for (int i = 0; i < this->stateEvaluator()->childEvaluators()->rowCount(); i++) {
|
||||
// ret->stateEvaluator()->childEvaluators()->
|
||||
// }
|
||||
for (int i = 0; i < this->timeDescriptor()->timeEventItems()->rowCount(); i++) {
|
||||
ret->timeDescriptor()->timeEventItems()->addTimeEventItem(this->timeDescriptor()->timeEventItems()->get(i)->clone());
|
||||
}
|
||||
for (int i = 0; i < this->timeDescriptor()->calendarItems()->rowCount(); i++) {
|
||||
ret->timeDescriptor()->calendarItems()->addCalendarItem(this->timeDescriptor()->calendarItems()->get(i)->clone());
|
||||
}
|
||||
if (this->stateEvaluator()) {
|
||||
ret->setStateEvaluator(this->stateEvaluator()->clone());
|
||||
}
|
||||
for (int i = 0; i < this->actions()->rowCount(); i++) {
|
||||
ret->actions()->addRuleAction(this->actions()->get(i)->clone());
|
||||
}
|
||||
|
||||
@ -23,6 +23,7 @@ class Rule : public QObject
|
||||
Q_PROPERTY(TimeDescriptor* timeDescriptor READ timeDescriptor CONSTANT)
|
||||
public:
|
||||
explicit Rule(const QUuid &id = QUuid(), QObject *parent = nullptr);
|
||||
~Rule();
|
||||
|
||||
QUuid id() const;
|
||||
|
||||
@ -45,7 +46,7 @@ public:
|
||||
|
||||
Q_INVOKABLE void createStateEvaluator();
|
||||
|
||||
Rule *clone() const;
|
||||
Q_INVOKABLE Rule *clone() const;
|
||||
|
||||
signals:
|
||||
void nameChanged();
|
||||
|
||||
@ -59,3 +59,17 @@ StateEvaluator* StateEvaluator::addChildEvaluator()
|
||||
m_childEvaluators->addStateEvaluator(stateEvaluator);
|
||||
return stateEvaluator;
|
||||
}
|
||||
|
||||
StateEvaluator *StateEvaluator::clone() const
|
||||
{
|
||||
StateEvaluator *ret = new StateEvaluator();
|
||||
ret->m_operator = this->m_operator;
|
||||
ret->m_stateDescriptor->setDeviceId(this->m_stateDescriptor->deviceId());
|
||||
ret->m_stateDescriptor->setStateTypeId(this->m_stateDescriptor->stateTypeId());
|
||||
ret->m_stateDescriptor->setValueOperator(this->m_stateDescriptor->valueOperator());
|
||||
ret->m_stateDescriptor->setValue(this->m_stateDescriptor->value());
|
||||
for (int i = 0; i < this->m_childEvaluators->rowCount(); i++) {
|
||||
ret->m_childEvaluators->addStateEvaluator(this->m_childEvaluators->get(i)->clone());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -33,6 +33,8 @@ public:
|
||||
|
||||
Q_INVOKABLE StateEvaluator* addChildEvaluator();
|
||||
|
||||
StateEvaluator* clone() const;
|
||||
|
||||
signals:
|
||||
void stateOperatorChanged();
|
||||
|
||||
|
||||
@ -1,6 +1,20 @@
|
||||
#include "timedescriptor.h"
|
||||
|
||||
#include "timeeventitems.h"
|
||||
#include "calendaritems.h"
|
||||
|
||||
TimeDescriptor::TimeDescriptor(QObject *parent) : QObject(parent)
|
||||
{
|
||||
|
||||
m_timeEventItems = new TimeEventItems(this);
|
||||
m_calendarItems = new CalendarItems(this);
|
||||
}
|
||||
|
||||
TimeEventItems *TimeDescriptor::timeEventItems() const
|
||||
{
|
||||
return m_timeEventItems;
|
||||
}
|
||||
|
||||
CalendarItems *TimeDescriptor::calendarItems() const
|
||||
{
|
||||
return m_calendarItems;
|
||||
}
|
||||
|
||||
@ -3,15 +3,28 @@
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include <QAbstractListModel>
|
||||
|
||||
class TimeEventItems;
|
||||
class CalendarItems;
|
||||
|
||||
class TimeDescriptor : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(TimeEventItems* timeEventItems READ timeEventItems CONSTANT)
|
||||
Q_PROPERTY(CalendarItems* calendarItems READ calendarItems CONSTANT)
|
||||
public:
|
||||
explicit TimeDescriptor(QObject *parent = nullptr);
|
||||
|
||||
TimeEventItems* timeEventItems() const;
|
||||
CalendarItems* calendarItems() const;
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
|
||||
private:
|
||||
TimeEventItems* m_timeEventItems = nullptr;
|
||||
CalendarItems* m_calendarItems = nullptr;
|
||||
};
|
||||
|
||||
#endif // TIMEDESCRIPTOR_H
|
||||
#endif // TIMEDESCRIPTOR_H
|
||||
|
||||
@ -1,8 +1,11 @@
|
||||
#include "timeeventitem.h"
|
||||
|
||||
TimeEventItem::TimeEventItem(QObject *parent) : QObject(parent)
|
||||
{
|
||||
#include "repeatingoption.h"
|
||||
|
||||
TimeEventItem::TimeEventItem(QObject *parent):
|
||||
QObject(parent),
|
||||
m_repeatingOption(new RepeatingOption(this))
|
||||
{
|
||||
}
|
||||
|
||||
QDateTime TimeEventItem::dateTime() const
|
||||
@ -30,3 +33,17 @@ void TimeEventItem::setTime(const QTime &time)
|
||||
emit timeChanged();
|
||||
}
|
||||
}
|
||||
|
||||
RepeatingOption *TimeEventItem::repeatingOption() const
|
||||
{
|
||||
return m_repeatingOption;
|
||||
}
|
||||
|
||||
TimeEventItem *TimeEventItem::clone() const
|
||||
{
|
||||
TimeEventItem* ret = new TimeEventItem();
|
||||
ret->m_dateTime = this->m_dateTime;
|
||||
ret->m_time = this->m_time;
|
||||
ret->m_repeatingOption = this->m_repeatingOption;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -5,11 +5,14 @@
|
||||
#include <QDateTime>
|
||||
#include <QTime>
|
||||
|
||||
class RepeatingOption;
|
||||
|
||||
class TimeEventItem : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(QDateTime dateTime READ dateTime WRITE setDateTime NOTIFY dateTimeChanged)
|
||||
Q_PROPERTY(QTime time READ time WRITE setTime NOTIFY timeChanged)
|
||||
Q_PROPERTY(RepeatingOption* repeatingOption READ repeatingOption CONSTANT)
|
||||
|
||||
public:
|
||||
explicit TimeEventItem(QObject *parent = nullptr);
|
||||
@ -20,6 +23,10 @@ public:
|
||||
QTime time() const;
|
||||
void setTime(const QTime &time);
|
||||
|
||||
RepeatingOption* repeatingOption() const;
|
||||
|
||||
TimeEventItem* clone() const;
|
||||
|
||||
signals:
|
||||
void dateTimeChanged();
|
||||
void timeChanged();
|
||||
@ -27,6 +34,7 @@ signals:
|
||||
private:
|
||||
QDateTime m_dateTime;
|
||||
QTime m_time;
|
||||
RepeatingOption *m_repeatingOption = nullptr;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@ -1,6 +1,53 @@
|
||||
#include "timeeventitems.h"
|
||||
|
||||
TimeEventItems::TimeEventItems(QObject *parent) : QObject(parent)
|
||||
#include "timeeventitem.h"
|
||||
|
||||
TimeEventItems::TimeEventItems(QObject *parent):
|
||||
QAbstractListModel(parent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int TimeEventItems::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
Q_UNUSED(parent)
|
||||
return m_list.count();
|
||||
}
|
||||
|
||||
QVariant TimeEventItems::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
void TimeEventItems::addTimeEventItem(TimeEventItem *timeEventItem)
|
||||
{
|
||||
timeEventItem->setParent(this);
|
||||
beginInsertRows(QModelIndex(), m_list.count(), m_list.count());
|
||||
m_list.append(timeEventItem);
|
||||
endInsertRows();
|
||||
emit countChanged();
|
||||
}
|
||||
|
||||
void TimeEventItems::removeTimeEventItem(int index)
|
||||
{
|
||||
if (index < 0 || index > m_list.count()) {
|
||||
return;
|
||||
}
|
||||
beginRemoveRows(QModelIndex(), index, index);
|
||||
m_list.takeAt(index)->deleteLater();
|
||||
endRemoveRows();
|
||||
emit countChanged();
|
||||
}
|
||||
|
||||
TimeEventItem *TimeEventItems::get(int index) const
|
||||
{
|
||||
if (index < 0 || index > m_list.count()) {
|
||||
return nullptr;
|
||||
}
|
||||
return m_list.at(index);
|
||||
}
|
||||
|
||||
TimeEventItem *TimeEventItems::createNewTimeEventItem() const
|
||||
{
|
||||
return new TimeEventItem();
|
||||
}
|
||||
|
||||
@ -1,17 +1,32 @@
|
||||
#ifndef TIMEEVENTITEMS_H
|
||||
#define TIMEEVENTITEMS_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QAbstractListModel>
|
||||
|
||||
class TimeEventItems : public QObject
|
||||
class TimeEventItem;
|
||||
|
||||
class TimeEventItems: public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int count READ rowCount NOTIFY countChanged)
|
||||
public:
|
||||
explicit TimeEventItems(QObject *parent = nullptr);
|
||||
TimeEventItems(QObject *parent);
|
||||
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
|
||||
Q_INVOKABLE void addTimeEventItem(TimeEventItem *timeEventItem);
|
||||
Q_INVOKABLE void removeTimeEventItem(int index);
|
||||
|
||||
Q_INVOKABLE TimeEventItem* get(int index) const;
|
||||
Q_INVOKABLE TimeEventItem* createNewTimeEventItem() const;
|
||||
|
||||
|
||||
signals:
|
||||
void countChanged();
|
||||
|
||||
public slots:
|
||||
private:
|
||||
QList<TimeEventItem*> m_list;
|
||||
};
|
||||
|
||||
#endif // TIMEEVENTITEMS_H
|
||||
#endif // TIMEEVENTITEMS_H
|
||||
|
||||
@ -13,7 +13,7 @@ win32:Debug:LIBS += -L$$top_builddir/libmea-core/debug \
|
||||
win32:Release:LIBS += -L$$top_builddir/libmea-core/release \
|
||||
-L$$top_builddir/libnymea-common/release
|
||||
linux:!android:LIBS += -lavahi-client -lavahi-common
|
||||
PRE_TARGETDEPS += ../libmea-core
|
||||
PRE_TARGETDEPS += ../libmea-core ../libnymea-common
|
||||
HEADERS += \
|
||||
stylecontroller.h
|
||||
|
||||
|
||||
@ -187,5 +187,16 @@
|
||||
<file>../LICENSE</file>
|
||||
<file>ui/images/Built_with_Qt_RGB_logo.svg</file>
|
||||
<file>ui/images/Built_with_Qt_RGB_logo_vertical.svg</file>
|
||||
<file>ui/magic/TimeEventDelegate.qml</file>
|
||||
<file>ui/magic/EditTimeEventItemPage.qml</file>
|
||||
<file>ui/magic/EventDescriptorDelegate.qml</file>
|
||||
<file>ui/components/MeaDialog.qml</file>
|
||||
<file>ui/magic/RuleActionDelegate.qml</file>
|
||||
<file>ui/magic/EditCalendarItemPage.qml</file>
|
||||
<file>ui/magic/CalendarItemDelegate.qml</file>
|
||||
<file>ui/images/alarm-clock.svg</file>
|
||||
<file>ui/images/action.svg</file>
|
||||
<file>ui/images/event.svg</file>
|
||||
<file>ui/images/state.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
||||
@ -23,20 +23,23 @@ Page {
|
||||
popup.open();
|
||||
}
|
||||
onCreateUserFailed: {
|
||||
print("create user failed")
|
||||
var text
|
||||
print("createUser failed")
|
||||
var message;
|
||||
switch (error) {
|
||||
case "UserErrorInvalidUserId":
|
||||
text = qsTr("The email you've entered isn't valid.");
|
||||
message = qsTr("The email you've entered isn't valid.")
|
||||
break;
|
||||
case "UserErrorDuplicateUserId":
|
||||
message = qsTr("The email you've entered is already userd.")
|
||||
break;
|
||||
case "UserErrorBadPassword":
|
||||
text = qsTr("The password you've chose is too weak.");
|
||||
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;
|
||||
default:
|
||||
text = qsTr("An error happened creating the user.");
|
||||
}
|
||||
// var popup = errorDialog.createObject(root, {title: qsTr("Error creating user"), text: text})
|
||||
var popup = errorDialog.createObject(root, {title: "Error creating user", text: text})
|
||||
var popup = errorDialog.createObject(root, {text: message});
|
||||
popup.open();
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,30 +13,45 @@ Page {
|
||||
HeaderButton {
|
||||
imageSource: Qt.resolvedUrl("images/add.svg")
|
||||
onClicked: {
|
||||
var newRulePage = pageStack.push(Qt.resolvedUrl("magic/EditRulePage.qml"), {rule: Engine.ruleManager.createNewRule() });
|
||||
newRulePage.onAccept.connect(function() {
|
||||
Engine.ruleManager.addRule(newRulePage.rule);
|
||||
d.editRulePage = pageStack.push(Qt.resolvedUrl("magic/EditRulePage.qml"), {rule: Engine.ruleManager.createNewRule() });
|
||||
d.editRulePage.StackView.onRemoved.connect(function() {
|
||||
d.editRulePage.rule.destroy()
|
||||
d.editRulePage = null;
|
||||
})
|
||||
d.editRulePage.onAccept.connect(function() {
|
||||
d.editRulePage.busy = true;
|
||||
Engine.ruleManager.addRule(d.editRulePage.rule);
|
||||
})
|
||||
d.editRulePage.onCancel.connect(function() {
|
||||
pageStack.pop();
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
property var editRulePage: null
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: Engine.ruleManager
|
||||
onAddRuleReply: {
|
||||
d.editRulePage.busy = false;
|
||||
if (ruleError == "RuleErrorNoError") {
|
||||
pageStack.pop();
|
||||
} else {
|
||||
var popup = errorDialog.createObject(root, {text: ruleError })
|
||||
var popup = errorDialog.createObject(app, {errorCode: ruleError })
|
||||
popup.open();
|
||||
}
|
||||
}
|
||||
|
||||
onEditRuleReply: {
|
||||
d.editRulePage.busy = false;
|
||||
if (ruleError == "RuleErrorNoError") {
|
||||
pageStack.pop();
|
||||
} else {
|
||||
var popup = errorDialog.createObject(root, {text: ruleError })
|
||||
var popup = errorDialog.createObject(app, {errorCode: ruleError })
|
||||
popup.open();
|
||||
}
|
||||
}
|
||||
@ -66,10 +81,18 @@ Page {
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
var editRulePage = pageStack.push(Qt.resolvedUrl("magic/EditRulePage.qml"), {rule: Engine.ruleManager.rules.get(index) })
|
||||
editRulePage.onAccept.connect(function() {
|
||||
d.editRulePage = pageStack.push(Qt.resolvedUrl("magic/EditRulePage.qml"), {rule: Engine.ruleManager.rules.get(index).clone()})
|
||||
d.editRulePage.StackView.onRemoved.connect(function() {
|
||||
d.editRulePage.rule.destroy();
|
||||
d.editRulePage = null
|
||||
})
|
||||
d.editRulePage.onAccept.connect(function() {
|
||||
d.editRulePage.busy = true;
|
||||
Engine.ruleManager.editRule(editRulePage.rule);
|
||||
})
|
||||
d.editRulePage.onCancel.connect(function() {
|
||||
pageStack.pop();
|
||||
})
|
||||
}
|
||||
|
||||
swipe.right: MouseArea {
|
||||
|
||||
@ -22,6 +22,8 @@ ApplicationWindow {
|
||||
property int iconSize: 30
|
||||
property int delegateHeight: 60
|
||||
|
||||
property bool landscape: app.width > app.height
|
||||
|
||||
property var settings: Settings {
|
||||
property string lastConnectedHost: ""
|
||||
property int viewMode: ApplicationWindow.Maximized
|
||||
|
||||
@ -38,8 +38,9 @@ Page {
|
||||
target: networkManger.manager
|
||||
onErrorOccured: {
|
||||
print("Error occured", errorMessage)
|
||||
errorDialog.errorText = errorMessage
|
||||
errorDialog.open()
|
||||
var errorDialog = Qt.createComponent(Qt.resolvedUrl("components/ErrorDialog.qml"));
|
||||
var popup = errorDialog.createObject(app, {text: errorMessage})
|
||||
popup.open()
|
||||
}
|
||||
|
||||
onWirelessStatusChanged: {
|
||||
@ -287,28 +288,6 @@ Page {
|
||||
}
|
||||
|
||||
|
||||
Dialog {
|
||||
id: errorDialog
|
||||
width: Math.min(parent.width * .9, 400)
|
||||
x: (parent.width - width) / 2
|
||||
y: (parent.height - height) / 2
|
||||
standardButtons: Dialog.Ok
|
||||
|
||||
property string errorText
|
||||
|
||||
ColumnLayout {
|
||||
anchors { left: parent.left; right: parent.right; top: parent.top }
|
||||
spacing: app.margins
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
wrapMode: Text.WordWrap
|
||||
text: errorDialog.errorText
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Component {
|
||||
id: settingsPage
|
||||
|
||||
|
||||
@ -2,51 +2,15 @@ import QtQuick 2.8
|
||||
import QtQuick.Controls 2.1
|
||||
import QtQuick.Layouts 1.2
|
||||
|
||||
Dialog {
|
||||
MeaDialog {
|
||||
id: root
|
||||
width: Math.min(parent.width * .8, contentLabel.implicitWidth)
|
||||
x: (parent.width - width) / 2
|
||||
y: (parent.height - height) / 2
|
||||
modal: true
|
||||
|
||||
title: qsTr("Error")
|
||||
property alias text: contentLabel.text
|
||||
title: qsTr("Oh snap!")
|
||||
headerIcon: "../images/dialog-error-symbolic.svg"
|
||||
|
||||
standardButtons: Dialog.Ok
|
||||
property string errorCode: ""
|
||||
|
||||
header: Item {
|
||||
implicitHeight: headerRow.height + app.margins * 2
|
||||
implicitWidth: parent.width
|
||||
RowLayout {
|
||||
id: headerRow
|
||||
anchors { left: parent.left; right: parent.right; top: parent.top; margins: app.margins }
|
||||
spacing: app.margins
|
||||
ColorIcon {
|
||||
Layout.preferredHeight: app.iconSize * 2
|
||||
Layout.preferredWidth: height
|
||||
name: "../images/dialog-error-symbolic.svg"
|
||||
color: app.guhAccent
|
||||
}
|
||||
text: qsTr("An unexpected error happened. We're sorry for that.") +
|
||||
(errorCode.length > 0 ? "\n\n" + qsTr("Error code: %1").arg(errorCode) : "")
|
||||
|
||||
Label {
|
||||
id: titleLabel
|
||||
Layout.fillWidth: true
|
||||
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
||||
text: root.title
|
||||
color: app.guhAccent
|
||||
font.pixelSize: app.largeFont
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: content
|
||||
anchors { left: parent.left; top: parent.top; right: parent.right }
|
||||
|
||||
Label {
|
||||
id: contentLabel
|
||||
Layout.fillWidth: true
|
||||
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
54
mea/ui/components/MeaDialog.qml
Normal file
54
mea/ui/components/MeaDialog.qml
Normal file
@ -0,0 +1,54 @@
|
||||
import QtQuick 2.8
|
||||
import QtQuick.Controls 2.1
|
||||
import QtQuick.Layouts 1.2
|
||||
|
||||
Dialog {
|
||||
id: root
|
||||
width: Math.min(parent.width * .8, Math.max(contentLabel.implicitWidth, 400))
|
||||
x: (parent.width - width) / 2
|
||||
y: (parent.height - height) / 2
|
||||
|
||||
property alias headerIcon: headerColorIcon.name
|
||||
property alias text: contentLabel.text
|
||||
default property alias children: content.children
|
||||
|
||||
standardButtons: Dialog.Ok
|
||||
|
||||
header: Item {
|
||||
implicitHeight: headerRow.height + app.margins * 2
|
||||
implicitWidth: parent.width
|
||||
RowLayout {
|
||||
id: headerRow
|
||||
anchors { left: parent.left; right: parent.right; top: parent.top; margins: app.margins }
|
||||
spacing: app.margins
|
||||
ColorIcon {
|
||||
id: headerColorIcon
|
||||
Layout.preferredHeight: app.iconSize * 2
|
||||
Layout.preferredWidth: height
|
||||
color: app.guhAccent
|
||||
visible: name.length > 0
|
||||
}
|
||||
|
||||
Label {
|
||||
id: titleLabel
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: app.margins
|
||||
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
||||
text: root.title
|
||||
color: app.guhAccent
|
||||
font.pixelSize: app.largeFont
|
||||
}
|
||||
}
|
||||
}
|
||||
ColumnLayout {
|
||||
id: content
|
||||
anchors { left: parent.left; top: parent.top; right: parent.right }
|
||||
|
||||
Label {
|
||||
id: contentLabel
|
||||
Layout.fillWidth: true
|
||||
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
|
||||
visible: text.length > 0
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -39,60 +39,72 @@ Item {
|
||||
model: logsModel
|
||||
clip: true
|
||||
onCountChanged: positionViewAtEnd()
|
||||
delegate: ItemDelegate {
|
||||
delegate: SwipeDelegate {
|
||||
id: logEntryDelegate
|
||||
width: parent.width
|
||||
implicitHeight: app.delegateHeight
|
||||
contentItem: RowLayout {
|
||||
ColorIcon {
|
||||
Layout.preferredHeight: app.iconSize
|
||||
Layout.preferredWidth: height
|
||||
name: "../images/event.svg"
|
||||
color: app.guhAccent
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
RowLayout {
|
||||
Label {
|
||||
id: timeStampLabel
|
||||
Layout.fillWidth: true
|
||||
|
||||
ColorIcon {
|
||||
Layout.preferredHeight: timeStampLabel.height
|
||||
Layout.preferredWidth: height
|
||||
name: "../images/clock-app-symbolic.svg"
|
||||
}
|
||||
|
||||
Label {
|
||||
id: timeStampLabel
|
||||
Layout.fillWidth: true
|
||||
text: Qt.formatDateTime(model.timestamp,"dd.MM.yy - hh:mm:ss")
|
||||
}
|
||||
text: Qt.formatDateTime(model.timestamp,"dd.MM.yy - hh:mm:ss")
|
||||
}
|
||||
RowLayout {
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
Label {
|
||||
text: qsTr("Data:")
|
||||
}
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
text: model.value.trim()
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
text: qsTr("Data: %1").arg(model.value.trim())
|
||||
elide: Text.ElideRight
|
||||
font.pixelSize: app.smallFont
|
||||
}
|
||||
}
|
||||
HeaderButton {
|
||||
imageSource: "../images/magic.svg"
|
||||
color: {
|
||||
for (var i = 0; i < rulesFilterModel.count; i++) {
|
||||
var rule = rulesFilterModel.get(i);
|
||||
for (var j = 0; j < rule.eventDescriptors.count; j++) {
|
||||
var eventDescriptor = rule.eventDescriptors.get(j);
|
||||
if (eventDescriptor.eventTypeId === root.logsModel.typeId) {
|
||||
var matching = true;
|
||||
for (var k = 0; k < eventDescriptor.paramDescriptors.count; k++) {
|
||||
var paramDescriptor = eventDescriptor.paramDescriptors.get(k);
|
||||
if (paramDescriptor.value === model.value) {
|
||||
return app.guhAccent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return keyColor;
|
||||
}
|
||||
// ColorIcon {
|
||||
// Layout.preferredWidth: app.iconSize
|
||||
// Layout.preferredHeight: width
|
||||
// name: "../images/magic.svg"
|
||||
// color: {
|
||||
// for (var i = 0; i < rulesFilterModel.count; i++) {
|
||||
// var rule = rulesFilterModel.get(i);
|
||||
// for (var j = 0; j < rule.eventDescriptors.count; j++) {
|
||||
// var eventDescriptor = rule.eventDescriptors.get(j);
|
||||
// if (eventDescriptor.eventTypeId === root.logsModel.typeId) {
|
||||
// var matching = true;
|
||||
// for (var k = 0; k < eventDescriptor.paramDescriptors.count; k++) {
|
||||
// var paramDescriptor = eventDescriptor.paramDescriptors.get(k);
|
||||
// if (paramDescriptor.value === model.value) {
|
||||
// return app.guhAccent;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return keyColor;
|
||||
// }
|
||||
|
||||
onClicked: root.addRuleClicked(model.value)
|
||||
// }
|
||||
}
|
||||
swipe.right: MouseArea {
|
||||
height: logEntryDelegate.height
|
||||
width: height
|
||||
anchors.right: parent.right
|
||||
ColorIcon {
|
||||
anchors.fill: parent
|
||||
anchors.margins: app.margins
|
||||
name: "../images/magic.svg"
|
||||
}
|
||||
onClicked: root.addRuleClicked(model.value)
|
||||
}
|
||||
onClicked: {
|
||||
if (swipe.complete) {
|
||||
swipe.close()
|
||||
} else {
|
||||
swipe.open(SwipeDelegate.Right)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -51,7 +51,7 @@ Page {
|
||||
popup.open();
|
||||
return;
|
||||
default:
|
||||
var popup = errorDialog.createObject(root, {text: qsTr("Remove device error: %1").arg(JSON.stringify(params.deviceError)) })
|
||||
var popup = errorDialog.createObject(root, {errorCode: params.deviceError})
|
||||
popup.open();
|
||||
}
|
||||
}
|
||||
|
||||
172
mea/ui/images/action.svg
Normal file
172
mea/ui/images/action.svg
Normal file
@ -0,0 +1,172 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="96"
|
||||
height="96"
|
||||
id="svg4874"
|
||||
version="1.1"
|
||||
inkscape:version="0.92.3 (2405546, 2018-03-11)"
|
||||
viewBox="0 0 96 96.000001"
|
||||
sodipodi:docname="action.svg">
|
||||
<defs
|
||||
id="defs4876" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="14.049998"
|
||||
inkscape:cx="54.082123"
|
||||
inkscape:cy="46.974137"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
showborder="true"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:bbox-paths="true"
|
||||
inkscape:bbox-nodes="true"
|
||||
inkscape:snap-bbox-edge-midpoints="true"
|
||||
inkscape:snap-bbox-midpoints="true"
|
||||
inkscape:object-paths="true"
|
||||
inkscape:snap-intersection-paths="true"
|
||||
inkscape:object-nodes="true"
|
||||
inkscape:snap-smooth-nodes="true"
|
||||
inkscape:snap-midpoints="true"
|
||||
inkscape:snap-object-midpoints="true"
|
||||
inkscape:snap-center="true"
|
||||
showguides="true"
|
||||
inkscape:guide-bbox="true"
|
||||
inkscape:snap-global="true"
|
||||
inkscape:window-width="2880"
|
||||
inkscape:window-height="1698"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="44"
|
||||
inkscape:window-maximized="1">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid5451"
|
||||
empspacing="8" />
|
||||
<sodipodi:guide
|
||||
orientation="1,0"
|
||||
position="8,-8.0000001"
|
||||
id="guide4063"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
orientation="1,0"
|
||||
position="4,-8.0000001"
|
||||
id="guide4065"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
orientation="0,1"
|
||||
position="-8,88.000001"
|
||||
id="guide4067"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
orientation="0,1"
|
||||
position="-8,92.000001"
|
||||
id="guide4069"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
orientation="0,1"
|
||||
position="104,4"
|
||||
id="guide4071"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
orientation="0,1"
|
||||
position="-5,8.0000001"
|
||||
id="guide4073"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
orientation="1,0"
|
||||
position="88,-8.0000001"
|
||||
id="guide4077"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
orientation="0,1"
|
||||
position="-8,84.000001"
|
||||
id="guide4074"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
orientation="1,0"
|
||||
position="12,-8.0000001"
|
||||
id="guide4076"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
orientation="1,0"
|
||||
position="84,-8.0000001"
|
||||
id="guide4080"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
position="48,-8.0000001"
|
||||
orientation="1,0"
|
||||
id="guide4170"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
position="-8,48"
|
||||
orientation="0,1"
|
||||
id="guide4172"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
position="92,-8.0000001"
|
||||
orientation="1,0"
|
||||
id="guide4760"
|
||||
inkscape:locked="false" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata4879">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(67.857146,-78.50504)">
|
||||
<rect
|
||||
transform="rotate(90)"
|
||||
y="-28.142855"
|
||||
x="78.505043"
|
||||
height="96"
|
||||
width="96"
|
||||
id="rect4782-637"
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;stroke:none;stroke-width:3.99999976;marker:none;enable-background:accumulate" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="rect4747-4"
|
||||
d="m 18.142883,124.50503 1.000025,3.99998 h -32.999999 v -3.99998 z"
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#808080;fill-opacity:1;stroke:none;stroke-width:8.99999905;marker:none;enable-background:accumulate"
|
||||
inkscape:transform-center-x="-26.500014" />
|
||||
<path
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:none;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3.99999976;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="M 5.6230724,101.05661 C -4.6712646,90.767855 -20.167327,87.685805 -33.61715,93.253885 c -13.44979,5.56807 -22.23047,18.700765 -22.23047,33.251945 0,14.55118 8.78068,27.68194 22.23047,33.25002 13.449823,5.56804 28.9458854,2.48602 39.2402224,-7.80276 l -2.828107,-2.82811 c -9.158173,9.15322 -22.9166364,11.88745 -34.8828054,6.93358 -11.96618,-4.95383 -19.75979,-16.60879 -19.75979,-29.55273 0,-12.94393 7.79361,-24.60083 19.75979,-29.554705 11.966169,-4.95382 25.7246324,-2.2196 34.8828054,6.933635 z"
|
||||
id="path4145"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path5837"
|
||||
d="m 5.1430854,114.50443 0.0076,24 c 3.6500406,-1.66873 7.3659206,-3.53593 11.1491896,-5.59872 3.747742,-2.06778 7.362822,-4.2005 10.84286,-6.40026 -3.480038,-2.15576 -7.095118,-4.26806 -10.84286,-6.33584 -3.785348,-2.06393 -7.503345,-3.95188 -11.1553126,-5.66518 z"
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.99940658;marker:none;enable-background:accumulate" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.0 KiB |
197
mea/ui/images/alarm-clock.svg
Normal file
197
mea/ui/images/alarm-clock.svg
Normal file
@ -0,0 +1,197 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="96"
|
||||
height="96"
|
||||
id="svg4874"
|
||||
version="1.1"
|
||||
inkscape:version="0.91+devel r"
|
||||
viewBox="0 0 96 96.000001"
|
||||
sodipodi:docname="reminder.svg">
|
||||
<defs
|
||||
id="defs4876" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="5.6199993"
|
||||
inkscape:cx="4.0836252"
|
||||
inkscape:cy="58.033793"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="g4780"
|
||||
showgrid="true"
|
||||
showborder="true"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:bbox-paths="true"
|
||||
inkscape:bbox-nodes="true"
|
||||
inkscape:snap-bbox-edge-midpoints="true"
|
||||
inkscape:snap-bbox-midpoints="true"
|
||||
inkscape:object-paths="true"
|
||||
inkscape:snap-intersection-paths="true"
|
||||
inkscape:object-nodes="true"
|
||||
inkscape:snap-smooth-nodes="true"
|
||||
inkscape:snap-midpoints="true"
|
||||
inkscape:snap-object-midpoints="true"
|
||||
inkscape:snap-center="true"
|
||||
showguides="true"
|
||||
inkscape:guide-bbox="true">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid5451"
|
||||
empspacing="8" />
|
||||
<sodipodi:guide
|
||||
orientation="1,0"
|
||||
position="8,-8.0000001"
|
||||
id="guide4063" />
|
||||
<sodipodi:guide
|
||||
orientation="1,0"
|
||||
position="4,-8.0000001"
|
||||
id="guide4065" />
|
||||
<sodipodi:guide
|
||||
orientation="0,1"
|
||||
position="-8,88.000001"
|
||||
id="guide4067" />
|
||||
<sodipodi:guide
|
||||
orientation="0,1"
|
||||
position="-8,92.000001"
|
||||
id="guide4069" />
|
||||
<sodipodi:guide
|
||||
orientation="0,1"
|
||||
position="104,4"
|
||||
id="guide4071" />
|
||||
<sodipodi:guide
|
||||
orientation="0,1"
|
||||
position="-5,8.0000001"
|
||||
id="guide4073" />
|
||||
<sodipodi:guide
|
||||
orientation="1,0"
|
||||
position="92,-8.0000001"
|
||||
id="guide4075" />
|
||||
<sodipodi:guide
|
||||
orientation="1,0"
|
||||
position="88,-8.0000001"
|
||||
id="guide4077" />
|
||||
<sodipodi:guide
|
||||
orientation="0,1"
|
||||
position="-8,84.000001"
|
||||
id="guide4074" />
|
||||
<sodipodi:guide
|
||||
orientation="1,0"
|
||||
position="12,-8.0000001"
|
||||
id="guide4076" />
|
||||
<sodipodi:guide
|
||||
orientation="0,1"
|
||||
position="-5,12"
|
||||
id="guide4078" />
|
||||
<sodipodi:guide
|
||||
orientation="1,0"
|
||||
position="84,-9.0000001"
|
||||
id="guide4080" />
|
||||
<sodipodi:guide
|
||||
position="48,-8.0000001"
|
||||
orientation="1,0"
|
||||
id="guide4170" />
|
||||
<sodipodi:guide
|
||||
position="-8,48"
|
||||
orientation="0,1"
|
||||
id="guide4172" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata4879">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(67.857146,-78.50504)">
|
||||
<g
|
||||
transform="matrix(0,-1,-1,0,373.50506,516.50504)"
|
||||
id="g4845"
|
||||
style="display:inline">
|
||||
<g
|
||||
inkscape:export-ydpi="90"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-filename="next01.png"
|
||||
transform="matrix(-0.9996045,0,0,1,575.94296,-611.00001)"
|
||||
id="g4778"
|
||||
inkscape:label="Layer 1">
|
||||
<g
|
||||
transform="matrix(-1,0,0,1,575.99999,611)"
|
||||
id="g4780"
|
||||
style="display:inline">
|
||||
<rect
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;stroke:none;stroke-width:4;marker:none;enable-background:accumulate"
|
||||
id="rect4782"
|
||||
width="96.037987"
|
||||
height="96"
|
||||
x="-438.00244"
|
||||
y="345.36221"
|
||||
transform="scale(-1,1)" />
|
||||
<path
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;line-height:125%;font-family:Ubuntu;-inkscape-font-specification:Ubuntu;text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#808080;fill-opacity:1;stroke:none"
|
||||
d="m 364.0904,368.96573 c -0.0215,-0.0161 -0.0354,-0.0404 -0.0567,-0.0566 -0.0253,-0.0201 -0.057,-0.0305 -0.0821,-0.0508 z"
|
||||
id="path4157" />
|
||||
<path
|
||||
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;line-height:125%;font-family:Ubuntu;-inkscape-font-specification:Ubuntu;text-align:center;letter-spacing:0px;word-spacing:0px;writing-mode:lr-tb;text-anchor:middle;fill:#808080;fill-opacity:1;stroke:none"
|
||||
d="m 364.07673,417.80167 -0.13873,0.10742 c 0.0251,-0.0203 0.0569,-0.0307 0.0821,-0.0508 0.0214,-0.0162 0.0353,-0.0405 0.0567,-0.0566 z"
|
||||
id="path4344" />
|
||||
<path
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:normal;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:6;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m 417.99454,395.36222 -3.75148,0 -22.5089,0 -3.75149,0 0,-3.99941 3.75149,0 22.5089,0 3.75148,0 0,3.99941 z"
|
||||
id="path5329"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:normal;font-family:sans-serif;-inkscape-font-specification:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:6;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m 391.98425,395.36222 -4.00329,0 0,-3.7143 0,-18.57141 0,-3.71429 4.00329,0 0,3.71429 0,18.57141 0,3.7143 z"
|
||||
id="path5331"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:none;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4.00079107;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m 432,393.36133 c 0,23.17267 -18.83507,42 -42.01562,42 -23.18056,0 -42.01758,-18.82733 -42.01758,-42 0,-23.17267 18.83702,-42 42.01758,-42 23.18055,0 42.01562,18.82733 42.01562,42 z m -4.00195,0 c 0,-21.00963 -16.99445,-37.99805 -38.01367,-37.99805 -21.01923,0 -38.01563,16.98842 -38.01563,37.99805 0,21.00963 16.9964,38 38.01563,38 21.01922,0 38.01367,-16.99037 38.01367,-38 z"
|
||||
id="path4151"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
inkscape:transform-center-y="-28.541779"
|
||||
sodipodi:nodetypes="zscccsz"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4187"
|
||||
d="m 427.05076,356.30961 c 9.26681,9.26315 9.26681,13.89473 0,23.15787 l -0.8205,0.82018 c -1.47358,-5.56141 -4.38677,-10.63666 -8.44632,-14.71491 -4.0766,-4.05955 -9.15035,-6.97497 -14.71167,-8.45201 l 0.81144,-0.81113 c 9.26682,-9.26316 13.90023,-9.26316 23.16705,0 z"
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#808080;stroke:none;stroke-width:9;marker:none;enable-background:accumulate"
|
||||
inkscape:transform-center-x="-28.537261" />
|
||||
<path
|
||||
inkscape:transform-center-x="28.541784"
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#808080;stroke:none;stroke-width:9;marker:none;enable-background:accumulate"
|
||||
d="m 427.05076,430.41481 c -9.26682,9.26316 -13.90023,9.26316 -23.16705,0 l -0.82049,-0.82018 c 5.56361,-1.47299 10.64087,-4.38503 14.72072,-8.44297 4.06116,-4.07499 6.97774,-9.14674 8.45537,-14.70585 l 0.81145,0.81112 c 9.26681,9.26315 9.26681,13.89473 0,23.15788 z"
|
||||
id="path4085"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="zscccsz"
|
||||
inkscape:transform-center-y="-28.537254" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 10 KiB |
180
mea/ui/images/event.svg
Normal file
180
mea/ui/images/event.svg
Normal file
@ -0,0 +1,180 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="96"
|
||||
height="96"
|
||||
id="svg4874"
|
||||
version="1.1"
|
||||
inkscape:version="0.92.3 (2405546, 2018-03-11)"
|
||||
viewBox="0 0 96 96.000001"
|
||||
sodipodi:docname="event.svg">
|
||||
<defs
|
||||
id="defs4876" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="28.099996"
|
||||
inkscape:cx="22.257505"
|
||||
inkscape:cy="41.601488"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
showborder="true"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:bbox-paths="true"
|
||||
inkscape:bbox-nodes="true"
|
||||
inkscape:snap-bbox-edge-midpoints="true"
|
||||
inkscape:snap-bbox-midpoints="true"
|
||||
inkscape:object-paths="true"
|
||||
inkscape:snap-intersection-paths="true"
|
||||
inkscape:object-nodes="true"
|
||||
inkscape:snap-smooth-nodes="true"
|
||||
inkscape:snap-midpoints="true"
|
||||
inkscape:snap-object-midpoints="true"
|
||||
inkscape:snap-center="true"
|
||||
showguides="true"
|
||||
inkscape:guide-bbox="true"
|
||||
inkscape:snap-global="true"
|
||||
inkscape:window-width="2880"
|
||||
inkscape:window-height="1698"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="44"
|
||||
inkscape:window-maximized="1">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid5451"
|
||||
empspacing="8" />
|
||||
<sodipodi:guide
|
||||
orientation="1,0"
|
||||
position="8,-8.0000001"
|
||||
id="guide4063"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
orientation="1,0"
|
||||
position="4,-8.0000001"
|
||||
id="guide4065"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
orientation="0,1"
|
||||
position="-8,88.000001"
|
||||
id="guide4067"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
orientation="0,1"
|
||||
position="-8,92.000001"
|
||||
id="guide4069"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
orientation="0,1"
|
||||
position="104,4"
|
||||
id="guide4071"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
orientation="0,1"
|
||||
position="-5,8.0000001"
|
||||
id="guide4073"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
orientation="1,0"
|
||||
position="88,-8.0000001"
|
||||
id="guide4077"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
orientation="0,1"
|
||||
position="-8,84.000001"
|
||||
id="guide4074"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
orientation="1,0"
|
||||
position="12,-8.0000001"
|
||||
id="guide4076"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
orientation="1,0"
|
||||
position="84,-8.0000001"
|
||||
id="guide4080"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
position="48,-8.0000001"
|
||||
orientation="1,0"
|
||||
id="guide4170"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
position="-8,48"
|
||||
orientation="0,1"
|
||||
id="guide4172"
|
||||
inkscape:locked="false" />
|
||||
<sodipodi:guide
|
||||
position="92,-8.0000001"
|
||||
orientation="1,0"
|
||||
id="guide4760"
|
||||
inkscape:locked="false" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata4879">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(67.857146,-78.50504)">
|
||||
<rect
|
||||
transform="rotate(90)"
|
||||
y="-28.142855"
|
||||
x="78.505043"
|
||||
height="96"
|
||||
width="96"
|
||||
id="rect4782-637"
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;stroke:none;stroke-width:3.99999976;marker:none;enable-background:accumulate" />
|
||||
<g
|
||||
id="g842"
|
||||
transform="matrix(-1,0,0,1,-39.714411,2.025e-5)">
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4145"
|
||||
d="M 5.6230724,101.05661 C -4.6712646,90.767855 -20.167327,87.685805 -33.61715,93.253885 c -13.44979,5.56807 -22.23047,18.700765 -22.23047,33.251945 0,14.55118 8.78068,27.68194 22.23047,33.25002 13.449823,5.56804 28.9458854,2.48602 39.2402224,-7.80276 l -2.828107,-2.82811 c -9.158173,9.15322 -22.9166364,11.88745 -34.8828054,6.93358 -11.96618,-4.95383 -19.75979,-16.60879 -19.75979,-29.55273 0,-12.94393 7.79361,-24.60083 19.75979,-29.554705 11.966169,-4.95382 25.7246324,-2.2196 34.8828054,6.933635 z"
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:none;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3.99999976;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
|
||||
<g
|
||||
transform="matrix(-1,0,0,1,13.285644,0)"
|
||||
id="g836">
|
||||
<path
|
||||
sodipodi:nodetypes="ccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="rect4747-4"
|
||||
d="m 18.142883,124.50503 1.000025,3.99998 h -32.999999 v -3.99998 z"
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:#808080;fill-opacity:1;stroke:none;stroke-width:8.99999905;marker:none;enable-background:accumulate"
|
||||
inkscape:transform-center-x="-26.500014" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path5837"
|
||||
d="m 5.1430854,114.50443 0.0076,24 c 3.6500406,-1.66873 7.3659206,-3.53593 11.1491896,-5.59872 3.747742,-2.06778 7.362822,-4.2005 10.84286,-6.40026 -3.480038,-2.15576 -7.095118,-4.26806 -10.84286,-6.33584 -3.785348,-2.06393 -7.503345,-3.95188 -11.1553126,-5.66518 z"
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.99940658;marker:none;enable-background:accumulate" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.3 KiB |
19
mea/ui/images/state.svg
Normal file
19
mea/ui/images/state.svg
Normal file
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg id="svg4874" width="96" height="96" version="1.1" viewBox="0 0 96 96" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
||||
<metadata id="metadata4879">
|
||||
<rdf:RDF>
|
||||
<cc:Work rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
|
||||
<dc:title/>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g id="layer1" transform="translate(67.857 -78.505)">
|
||||
<rect id="rect4782-2" transform="rotate(90)" x="78.505" y="-28.143" width="96" height="96" style="color:#000000;fill:none"/>
|
||||
<path id="path4643-2" d="m-39.869 98.504-0.01134 2e-3c-5.0328 0.0582-8.7136-0.12019-11.725 1.541-1.5055 0.83062-2.6968 2.2356-3.3555 3.9902-0.65866 1.7546-0.89647 3.8364-0.89647 6.4668v48.002c0 2.6304 0.23773 4.7122 0.89647 6.4668 0.65866 1.7546 1.85 3.1596 3.3555 3.9902 3.011 1.6613 6.6918 1.4848 11.725 1.543h0.01134 40.023 0.01134c5.0328-0.0582 8.7136 0.1183 11.725-1.543 1.5055-0.83066 2.6968-2.2356 3.3555-3.9902 0.65866-1.7546 0.8965-3.8364 0.8965-6.4668v-48.002c0-2.6304-0.23773-4.7122-0.8965-6.4668-0.65866-1.7547-1.85-3.1596-3.3555-3.9902-3.011-1.6613-6.6918-1.4829-11.725-1.5411l-0.01134-2e-3 -12.012 2e-3v4l11.977-2e-3c5.0542 0.0586 8.3726 0.23547 9.8398 1.0449 0.73364 0.40479 1.1527 0.85493 1.543 1.8945 0.39024 1.0396 0.64059 2.691 0.64059 5.0606v48.002c0 2.3695-0.2502 4.0209-0.64059 5.0605-0.39027 1.0396-0.80935 1.4898-1.543 1.8945-1.4645 0.80806-4.7782 0.98615-9.8164 1.0449h-39.977-0.02268c-5.0383-0.059-8.3519-0.23697-9.8164-1.0449-0.73364-0.40475-1.1508-0.85489-1.541-1.8945-0.39027-1.0396-0.6426-2.691-0.6426-5.0605v-48.002c0-2.3696 0.25247-4.0209 0.6426-5.0606 0.39024-1.0396 0.80734-1.4897 1.541-1.8945 1.4645-0.80807 4.7782-0.98616 9.8164-1.0449l12 2e-3v-4z" style="color-rendering:auto;color:#000000;fill:#808080;font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;image-rendering:auto;isolation:auto;mix-blend-mode:normal;shape-padding:0;shape-rendering:auto;solid-color:#000000;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-transform:none;white-space:normal"/>
|
||||
<path id="path4237" d="m-21.858 82.505v50h4v-50z" style="fill:#808080"/>
|
||||
<path id="path5588-9-2-96-04" d="m-7.8571 124.51-24 8e-3c1.6687 3.6501 3.5359 7.366 5.5987 11.149 2.0678 3.7477 4.2005 7.3628 6.4003 10.843 2.1557-3.48 4.268-7.0951 6.3358-10.843 2.0639-3.7854 3.9519-7.5033 5.6652-11.155z" style="color:#000000;fill:#808080"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.7 KiB |
111
mea/ui/magic/CalendarItemDelegate.qml
Normal file
111
mea/ui/magic/CalendarItemDelegate.qml
Normal file
@ -0,0 +1,111 @@
|
||||
import QtQuick 2.9
|
||||
import QtQuick.Controls 2.2
|
||||
import QtQuick.Layouts 1.3
|
||||
import Mea 1.0
|
||||
import "../components"
|
||||
|
||||
SwipeDelegate {
|
||||
id: root
|
||||
implicitHeight: app.delegateHeight
|
||||
|
||||
property var calendarItem: null
|
||||
|
||||
readonly property bool isDateBased: calendarItem.repeatingOption.repeatingMode === RepeatingOption.RepeatingModeNone ||
|
||||
calendarItem.repeatingOption.repeatingMode === RepeatingOption.RepeatingModeYearly
|
||||
|
||||
signal removeCalendarItem();
|
||||
|
||||
contentItem: RowLayout {
|
||||
spacing: app.margins
|
||||
ColorIcon {
|
||||
Layout.preferredHeight: app.iconSize
|
||||
Layout.preferredWidth: app.iconSize
|
||||
name: "../images/clock-app-symbolic.svg"
|
||||
color: app.guhAccent
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
elide: Text.ElideRight
|
||||
text: qsTr("From %1 to %2")
|
||||
.arg(root.isDateBased ? Qt.formatDateTime(root.calendarItem.dateTime) : Qt.formatTime(root.calendarItem.startTime))
|
||||
.arg(root.isDateBased ? Qt.formatDateTime(new Date(root.calendarItem.dateTime.getTime() + root.calendarItem.duration * 60000)) : Qt.formatTime(new Date(root.calendarItem.startTime.getTime() + root.calendarItem.duration * 60000)))
|
||||
}
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
elide: Text.ElideRight
|
||||
font.pixelSize: app.smallFont
|
||||
text: qsTr("repeated %3")
|
||||
.arg(repeatingString)
|
||||
|
||||
property string repeatingString: {
|
||||
switch (root.calendarItem.repeatingOption.repeatingMode) {
|
||||
case RepeatingOption.RepeatingModeNone:
|
||||
return qsTr("never");
|
||||
case RepeatingOption.RepeatingModeHourly:
|
||||
return qsTr("hourly");
|
||||
case RepeatingOption.RepeatingModeDaily:
|
||||
return qsTr("daily");
|
||||
case RepeatingOption.RepeatingModeWeekly:
|
||||
var weekdays = []
|
||||
for (var i = 0; i < root.calendarItem.repeatingOption.weekDays.length; i++) {
|
||||
switch (root.calendarItem.repeatingOption.weekDays[i]) {
|
||||
case 1:
|
||||
weekdays.push(qsTr("Mon"));
|
||||
break;
|
||||
case 2:
|
||||
weekdays.push(qsTr("Tue"));
|
||||
break;
|
||||
case 3:
|
||||
weekdays.push(qsTr("Wed"));
|
||||
break;
|
||||
case 4:
|
||||
weekdays.push(qsTr("Thu"));
|
||||
break;
|
||||
case 5:
|
||||
weekdays.push(qsTr("Fri"));
|
||||
break;
|
||||
case 6:
|
||||
weekdays.push(qsTr("Sat"));
|
||||
break;
|
||||
case 7:
|
||||
weekdays.push(qsTr("Sun"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return qsTr("weekly on %1").arg(weekdays.join(', '));
|
||||
case RepeatingOption.RepeatingModeMonthly:
|
||||
return qsTr("monthly on the %1").arg(root.calendarItem.repeatingOption.monthDays.join(', '));
|
||||
case RepeatingOption.RepeatingModeYearly:
|
||||
return qsTr("every year");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
swipe.right: MouseArea {
|
||||
height: root.height
|
||||
width: height
|
||||
anchors.right: parent.right
|
||||
ColorIcon {
|
||||
anchors.fill: parent
|
||||
anchors.margins: app.margins
|
||||
name: "../images/delete.svg"
|
||||
color: "red"
|
||||
}
|
||||
onClicked: root.removeCalendarItem()
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
var page = pageStack.push(Qt.resolvedUrl("EditCalendarItemPage.qml"), {calendarItem: root.calendarItem})
|
||||
page.onBackPressed.connect(function() {pageStack.pop()})
|
||||
page.onDone.connect(function() {
|
||||
pageStack.pop()
|
||||
print("calendarItem.time is now", root.calendarItem.time)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -21,14 +21,23 @@ Page {
|
||||
}
|
||||
|
||||
// Rule is optional and might be initialized with anything wanted. A new, empty one will be created if null
|
||||
// This Page will take ownership of the rule and delete it eventually.
|
||||
function addRule(rule) {
|
||||
if (rule === null || rule === undefined) {
|
||||
rule = Engine.ruleManager.createNewRule();
|
||||
}
|
||||
var page = pageStack.push(Qt.resolvedUrl("EditRulePage.qml"), {rule: rule});
|
||||
page.onAccept.connect(function() {
|
||||
d.editRulePage = pageStack.push(Qt.resolvedUrl("EditRulePage.qml"), {rule: rule});
|
||||
d.editRulePage.StackView.onRemoved.connect(function() {
|
||||
d.editRulePage.rule.destroy();
|
||||
d.editRulePage = null
|
||||
})
|
||||
d.editRulePage.onAccept.connect(function() {
|
||||
d.editRulePage.busy = true;
|
||||
Engine.ruleManager.addRule(page.rule);
|
||||
})
|
||||
d.editRulePage.onCancel.connect(function() {
|
||||
pageStack.pop();
|
||||
})
|
||||
|
||||
// if (rule.eventDescriptors.count === 0) {
|
||||
// var eventDescriptor = rule.eventDescriptors.createNewEventDescriptor();
|
||||
@ -38,18 +47,32 @@ Page {
|
||||
|
||||
}
|
||||
|
||||
QtObject {
|
||||
id: d
|
||||
property var editRulePage: null
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: Engine.ruleManager
|
||||
onAddRuleReply: {
|
||||
d.editRulePage.busy = false;
|
||||
if (ruleError == "RuleErrorNoError") {
|
||||
pageStack.pop();
|
||||
} else {
|
||||
var errorDialog = Qt.createComponent(Qt.resolvedUrl("../components/ErrorDialog.qml"));
|
||||
var popup = errorDialog.createObject(root, {errorCode: ruleError })
|
||||
popup.open();
|
||||
}
|
||||
}
|
||||
|
||||
onEditRuleReply: {
|
||||
print("have add rule reply")
|
||||
d.editRulePage.busy = false;
|
||||
if (ruleError == "RuleErrorNoError") {
|
||||
pageStack.pop();
|
||||
} else {
|
||||
var errorDialog = Qt.createComponent(Qt.resolvedUrl("../components/ErrorDialog.qml"));
|
||||
var popup = errorDialog.createObject(root, {errorCode: ruleError })
|
||||
popup.open();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -72,7 +95,7 @@ Page {
|
||||
height: app.iconSize
|
||||
width: height
|
||||
name: "../images/magic.svg"
|
||||
color: !model.enabled ? "gray" : (model.active ? "red" : app.guhAccent)
|
||||
color: !model.enabled ? "red" : (model.active ? app.guhAccent : "grey")
|
||||
}
|
||||
|
||||
Label {
|
||||
@ -82,9 +105,16 @@ Page {
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
var editRulePage = pageStack.push(Qt.resolvedUrl("EditRulePage.qml"), {rule: rulesFilterModel.get(index) })
|
||||
editRulePage.onAccept.connect(function() {
|
||||
Engine.ruleManager.editRule(editRulePage.rule);
|
||||
d.editRulePage = pageStack.push(Qt.resolvedUrl("EditRulePage.qml"), {rule: rulesFilterModel.get(index).clone() })
|
||||
d.editRulePage.StackView.onRemoved.connect(function() {
|
||||
d.editRulePage.rule.destroy();
|
||||
})
|
||||
d.editRulePage.onAccept.connect(function() {
|
||||
d.editRulePage.busy = true
|
||||
Engine.ruleManager.editRule(d.editRulePage.rule);
|
||||
})
|
||||
d.editRulePage.onCancel.connect(function() {
|
||||
pageStack.pop();
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
402
mea/ui/magic/EditCalendarItemPage.qml
Normal file
402
mea/ui/magic/EditCalendarItemPage.qml
Normal file
@ -0,0 +1,402 @@
|
||||
import QtQuick 2.9
|
||||
import QtQuick.Controls 2.2
|
||||
import Qt.labs.calendar 1.0
|
||||
import QtQuick.Layouts 1.3
|
||||
import "../components"
|
||||
import Mea 1.0
|
||||
|
||||
Page {
|
||||
id: root
|
||||
|
||||
property var calendarItem: null
|
||||
|
||||
signal done()
|
||||
signal backPressed()
|
||||
|
||||
readonly property bool isDateBased: repeatingBox.currentIndex === 0 ||
|
||||
repeatingBox.currentIndex === 5
|
||||
readonly property bool isWeekDayBased: repeatingBox.currentIndex === 3
|
||||
readonly property bool isMonthDayBased: repeatingBox.currentIndex === 4
|
||||
|
||||
header: GuhHeader {
|
||||
text: qsTr("Pick a time frame")
|
||||
onBackPressed: root.backPressed();
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
var date = root.isDateBased ? root.calendarItem.dateTime : root.calendarItem.startTime
|
||||
print("starting with time:", root.calendarItem.startTime, root.calendarItem.dateTime)
|
||||
if (isNaN(date)) {
|
||||
console.log("Date in rule not valid, using current datetime");
|
||||
date = new Date();
|
||||
}
|
||||
hourBox.currentIndex = date.getHours();
|
||||
minuteBox.currentIndex = date.getMinutes();
|
||||
dayBox.currentIndex = date.getDate() - 1;
|
||||
monthBox.currentIndex = date.getMonth();
|
||||
print("should set year to", date.getFullYear())
|
||||
yearBox.currentIndex = date.getFullYear() - 1970;
|
||||
|
||||
var endDate = new Date(date.getTime() + root.calendarItem.duration * 60000);
|
||||
toHourBox.currentIndex = endDate.getHours();
|
||||
toMinuteBox.currentIndex = endDate.getMinutes();
|
||||
toDayBox.currentIndex = endDate.getDate() - 1;
|
||||
toMonthBox.currentIndex = endDate.getMonth();
|
||||
toYearBox.currentIndex = endDate.getFullYear() - 1970
|
||||
}
|
||||
|
||||
function pad(num, size) {
|
||||
var s = "000000000" + num;
|
||||
return s.substr(s.length-size);
|
||||
}
|
||||
|
||||
Flickable {
|
||||
anchors.fill: parent
|
||||
contentHeight: mainColumn.implicitHeight
|
||||
|
||||
ColumnLayout {
|
||||
id: mainColumn
|
||||
anchors { left: parent.left; top: parent.top; right: parent.right }
|
||||
|
||||
GridLayout {
|
||||
columns: app.landscape ? 2 : 1
|
||||
Layout.alignment: app.landscape ? Qt.AlignHCenter : Qt.AlignLeft
|
||||
Layout.margins: app.margins
|
||||
Layout.fillWidth: !app.landscape
|
||||
|
||||
Label {
|
||||
text: qsTr("From")
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
ComboBox {
|
||||
id: hourBox
|
||||
model: {
|
||||
if (!enabled) {
|
||||
return ["--"]
|
||||
}
|
||||
|
||||
var ret = [];
|
||||
for (var i = 0; i < 24; i++) {
|
||||
ret.push(pad(i, 2));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
enabled: repeatingBox.currentIndex !== 1
|
||||
}
|
||||
Label {
|
||||
text: ":"
|
||||
}
|
||||
ComboBox {
|
||||
id: minuteBox
|
||||
model: {
|
||||
var ret = [];
|
||||
for (var i = 0; i < 60; i++) {
|
||||
ret.push(pad(i, 2));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillHeight: !app.landscape
|
||||
Layout.topMargin: app.landscape ? app.margins : 0
|
||||
visible: root.isDateBased
|
||||
ComboBox {
|
||||
id: dayBox
|
||||
Layout.fillWidth: true
|
||||
model: {
|
||||
var ret = [];
|
||||
for (var i = 1; i < 31; i++) {
|
||||
ret.push(pad(i, 2));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
ComboBox {
|
||||
id: monthBox
|
||||
Layout.fillWidth: true
|
||||
model: [
|
||||
qsTr("Jan"),
|
||||
qsTr("Feb"),
|
||||
qsTr("Mar"),
|
||||
qsTr("Apr"),
|
||||
qsTr("May"),
|
||||
qsTr("Jun"),
|
||||
qsTr("Jul"),
|
||||
qsTr("Aug"),
|
||||
qsTr("Sep"),
|
||||
qsTr("Oct"),
|
||||
qsTr("Nov"),
|
||||
qsTr("Dez")
|
||||
]
|
||||
}
|
||||
ComboBox {
|
||||
id: yearBox
|
||||
Layout.fillWidth: true
|
||||
model: {
|
||||
var ret = [];
|
||||
for (var i = 1970; i < 2100; i++) {
|
||||
ret.push(i);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr("To")
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
ComboBox {
|
||||
id: toHourBox
|
||||
model: {
|
||||
if (!enabled) {
|
||||
return ["--"]
|
||||
}
|
||||
|
||||
var ret = [];
|
||||
for (var i = 0; i < 24; i++) {
|
||||
ret.push(pad(i, 2));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
enabled: repeatingBox.currentIndex !== 1
|
||||
}
|
||||
Label {
|
||||
text: ":"
|
||||
}
|
||||
ComboBox {
|
||||
id: toMinuteBox
|
||||
model: {
|
||||
var ret = [];
|
||||
for (var i = 0; i < 60; i++) {
|
||||
ret.push(pad(i, 2));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillHeight: !app.landscape
|
||||
Layout.topMargin: app.landscape ? app.margins : 0
|
||||
visible: root.isDateBased
|
||||
ComboBox {
|
||||
id: toDayBox
|
||||
Layout.fillWidth: true
|
||||
model: {
|
||||
var ret = [];
|
||||
for (var i = 1; i < 31; i++) {
|
||||
ret.push(pad(i, 2));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
onActivated: {
|
||||
var date = root.calendarItem.dateTime
|
||||
date.setDate(index)
|
||||
root.calendarItem.dateTime = date;
|
||||
}
|
||||
}
|
||||
ComboBox {
|
||||
id: toMonthBox
|
||||
Layout.fillWidth: true
|
||||
model: [
|
||||
qsTr("Jan"),
|
||||
qsTr("Feb"),
|
||||
qsTr("Mar"),
|
||||
qsTr("Apr"),
|
||||
qsTr("May"),
|
||||
qsTr("Jun"),
|
||||
qsTr("Jul"),
|
||||
qsTr("Aug"),
|
||||
qsTr("Sep"),
|
||||
qsTr("Oct"),
|
||||
qsTr("Nov"),
|
||||
qsTr("Dez")
|
||||
]
|
||||
}
|
||||
ComboBox {
|
||||
id: toYearBox
|
||||
Layout.fillWidth: true
|
||||
model: {
|
||||
var ret = [];
|
||||
for (var i = 1970; i < 2100; i++) {
|
||||
ret.push(i);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr("Repeat")
|
||||
Layout.topMargin: app.margins
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: app.landscape ? app.margins : 0
|
||||
|
||||
ComboBox {
|
||||
id: repeatingBox
|
||||
model: [qsTr("never"), qsTr("hourly"), qsTr("daily"), qsTr("weekly"), qsTr("monthly"), qsTr("yearly")]
|
||||
|
||||
currentIndex: {
|
||||
switch (root.calendarItem.repeatingOption.repeatingMode) {
|
||||
case RepeatingOption.RepeatingModeNone:
|
||||
return 0;
|
||||
case RepeatingOption.RepeatingModeHourly:
|
||||
return 1;
|
||||
case RepeatingOption.RepeatingModeDaily:
|
||||
return 2;
|
||||
case RepeatingOption.RepeatingModeWeekly:
|
||||
return 3;
|
||||
case RepeatingOption.RepeatingModeMonthly:
|
||||
return 4;
|
||||
case RepeatingOption.RepeatingModeYearly:
|
||||
return 5;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Label {
|
||||
text: qsTr("Weekdays")
|
||||
Layout.topMargin: app.margins
|
||||
visible: root.isWeekDayBased
|
||||
}
|
||||
|
||||
DayOfWeekRow {
|
||||
id: weekDayRow
|
||||
property var weekDays: root.calendarItem.repeatingOption.weekDays
|
||||
visible: root.isWeekDayBased
|
||||
Layout.fillWidth: !app.landscape
|
||||
Layout.topMargin: app.landscape ? app.margins : 0
|
||||
delegate: ToolButton {
|
||||
text: model.shortName
|
||||
checked: weekDayRow.weekDays.indexOf(index + 1) >= 0
|
||||
onClicked: {
|
||||
var copy = weekDayRow.weekDays
|
||||
var idx = copy.indexOf(index + 1);
|
||||
if (idx >= 0) {
|
||||
copy.splice(idx, 1);
|
||||
} else {
|
||||
copy.push(index + 1)
|
||||
}
|
||||
weekDayRow.weekDays = copy
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Label {
|
||||
text: qsTr("Day of month")
|
||||
Layout.topMargin: app.margins
|
||||
visible: root.isMonthDayBased
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
||||
}
|
||||
|
||||
GridLayout {
|
||||
id: monthDayGrid
|
||||
columns: Math.sqrt(children.length)
|
||||
Layout.fillWidth: !app.landscape
|
||||
Layout.topMargin: app.landscape ? app.margins : 0
|
||||
visible: root.isMonthDayBased
|
||||
property var monthDays: root.calendarItem.repeatingOption.monthDays
|
||||
Repeater {
|
||||
model: 31
|
||||
delegate: ToolButton {
|
||||
Layout.fillWidth: true
|
||||
checked: monthDayGrid.monthDays.indexOf(index + 1) >= 0
|
||||
text: modelData + 1
|
||||
onClicked: {
|
||||
var copy = monthDayGrid.monthDays
|
||||
var idx = copy.indexOf(index + 1);
|
||||
if (idx >= 0) {
|
||||
copy.splice(idx, 1);
|
||||
} else {
|
||||
copy.push(index + 1)
|
||||
}
|
||||
monthDayGrid.monthDays = copy
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Button {
|
||||
Layout.fillWidth: !app.landscape
|
||||
Layout.margins: app.margins
|
||||
Layout.alignment: Qt.AlignRight
|
||||
text: qsTr("OK")
|
||||
onClicked: {
|
||||
if (root.isDateBased) {
|
||||
var date = isNaN(root.calendarItem.dateTime) ? new Date() : root.calendarItem.dateTime
|
||||
date.setHours(hourBox.currentIndex);
|
||||
date.setMinutes(minuteBox.currentIndex);
|
||||
date.setDate(dayBox.currentIndex + 1);
|
||||
date.setMonth(monthBox.currentIndex);
|
||||
date.setFullYear(yearBox.currentText);
|
||||
root.calendarItem.dateTime = date;
|
||||
|
||||
var endDate = new Date();
|
||||
endDate.setHours(toHourBox.currentIndex);
|
||||
endDate.setMinutes(toMinuteBox.currentIndex);
|
||||
endDate.setDate(toDayBox.currentIndex + 1);
|
||||
endDate.setMilliseconds(toMonthBox.currentIndex);
|
||||
endDate.setFullYear(toYearBox.currentText);
|
||||
root.calendarItem.duration = (endDate.getTime() - date.getTime()) / 60000;
|
||||
} else {
|
||||
var time = isNaN(root.calendarItem.startTime) ? new Date() : root.calendarItem.startTime
|
||||
time.setHours(hourBox.currentIndex);
|
||||
time.setMinutes(minuteBox.currentIndex)
|
||||
root.calendarItem.startTime = time;
|
||||
|
||||
var endTime = new Date(time);
|
||||
endTime.setHours(toHourBox.currentIndex);
|
||||
endTime.setMinutes(toMinuteBox.currentIndex);
|
||||
root.calendarItem.duration = (endTime.getTime() - time.getTime()) / 60000;
|
||||
print("duration is", endTime.getTime() - time.getTime(), time, endTime, toMinuteBox.currentIndex)
|
||||
}
|
||||
|
||||
switch (repeatingBox.currentIndex) {
|
||||
case 0:
|
||||
root.calendarItem.repeatingOption.repeatingMode = RepeatingOption.RepeatingModeNone;
|
||||
break;
|
||||
case 1:
|
||||
root.calendarItem.repeatingOption.repeatingMode = RepeatingOption.RepeatingModeHourly;
|
||||
break;
|
||||
case 2:
|
||||
root.calendarItem.repeatingOption.repeatingMode = RepeatingOption.RepeatingModeDaily;
|
||||
break;
|
||||
case 3:
|
||||
root.calendarItem.repeatingOption.repeatingMode = RepeatingOption.RepeatingModeWeekly;
|
||||
break;
|
||||
case 4:
|
||||
root.calendarItem.repeatingOption.repeatingMode = RepeatingOption.RepeatingModeMonthly;
|
||||
break;
|
||||
case 5:
|
||||
root.calendarItem.repeatingOption.repeatingMode = RepeatingOption.RepeatingModeYearly;
|
||||
break;
|
||||
}
|
||||
|
||||
if (root.isWeekDayBased) {
|
||||
root.calendarItem.repeatingOption.weekDays = weekDayRow.weekDays;
|
||||
}
|
||||
if (root.isMonthDayBased) {
|
||||
root.calendarItem.repeatingOption.monthDays = monthDayGrid.monthDays;
|
||||
}
|
||||
|
||||
root.done()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -8,15 +8,17 @@ Page {
|
||||
id: root
|
||||
|
||||
property var rule: null
|
||||
property bool busy: false
|
||||
|
||||
signal accept();
|
||||
|
||||
onAccept: busyOverlay.opacity = 1
|
||||
|
||||
readonly property bool isStateBased: rule.eventDescriptors.count === 0
|
||||
readonly property bool actionsVisible: rule.eventDescriptors.count > 0 || rule.stateEvaluator !== null
|
||||
readonly property bool isEventBased: rule.eventDescriptors.count > 0 || rule.timeDescriptor.timeEventItems.count > 0
|
||||
readonly property bool isStateBased: (rule.stateEvaluator !== null || rule.timeDescriptor.calendarItems.count > 0) && !isEventBased
|
||||
readonly property bool actionsVisible: !isEmpty
|
||||
readonly property bool exitActionsVisible: actionsVisible && isStateBased
|
||||
readonly property bool hasExitActions: rule.exitActions.count > 0
|
||||
readonly property bool isEmpty: !isEventBased && !isStateBased
|
||||
|
||||
signal accept();
|
||||
signal cancel();
|
||||
|
||||
function addEventDescriptor() {
|
||||
var eventDescriptor = root.rule.eventDescriptors.createNewEventDescriptor();
|
||||
@ -41,6 +43,32 @@ Page {
|
||||
})
|
||||
}
|
||||
|
||||
function addTimeEventItem() {
|
||||
var timeEventItem = root.rule.timeDescriptor.timeEventItems.createNewTimeEventItem();
|
||||
var page = pageStack.push(Qt.resolvedUrl("EditTimeEventItemPage.qml"), {timeEventItem: timeEventItem});
|
||||
page.onBackPressed.connect(function() {
|
||||
pageStack.pop()
|
||||
timeEventItem.destroy();
|
||||
})
|
||||
page.onDone.connect(function() {
|
||||
root.rule.timeDescriptor.timeEventItems.addTimeEventItem(timeEventItem);
|
||||
pageStack.pop();
|
||||
})
|
||||
}
|
||||
|
||||
function addCalendarItem() {
|
||||
var calendarItem = root.rule.timeDescriptor.calendarItems.createNewCalendarItem();
|
||||
var page = pageStack.push(Qt.resolvedUrl("EditCalendarItemPage.qml"), {calendarItem: calendarItem});
|
||||
page.onBackPressed.connect(function() {
|
||||
pageStack.pop();
|
||||
calendarItem.destroy();
|
||||
})
|
||||
page.onDone.connect(function() {
|
||||
root.rule.timeDescriptor.calendarItems.addCalendarItem(calendarItem);
|
||||
pageStack.pop();
|
||||
})
|
||||
}
|
||||
|
||||
function editStateEvaluator() {
|
||||
print("opening page", root.rule.stateEvaluator)
|
||||
var page = pageStack.push(Qt.resolvedUrl("EditStateEvaluatorPage.qml"), { stateEvaluator: root.rule.stateEvaluator })
|
||||
@ -91,15 +119,14 @@ Page {
|
||||
}
|
||||
|
||||
header: GuhHeader {
|
||||
text: qsTr("New rule")
|
||||
onBackPressed: pageStack.pop()
|
||||
text: root.rule.name.length === 0 ? qsTr("Add new magic") : qsTr("Edit %1").arg(root.rule.name)
|
||||
onBackPressed: root.cancel()
|
||||
|
||||
HeaderButton {
|
||||
imageSource: "../images/tick.svg"
|
||||
enabled: actionsRepeater.count > 0 && root.rule.name.length > 0
|
||||
opacity: enabled ? 1 : .3
|
||||
onClicked: {
|
||||
root.accept()
|
||||
}
|
||||
onClicked: root.accept()
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,24 +136,47 @@ Page {
|
||||
|
||||
ColumnLayout {
|
||||
id: contentColumn
|
||||
anchors { left: parent.left; top: parent.top; right: parent.right; topMargin: app.margins }
|
||||
anchors { left: parent.left; top: parent.top; right: parent.right; }
|
||||
ColumnLayout {
|
||||
id: ruleSettings
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: app.margins
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
text: qsTr("Rule name")
|
||||
}
|
||||
TextField {
|
||||
Layout.fillWidth: true
|
||||
text: root.rule.name
|
||||
onTextChanged: {
|
||||
root.rule.name = text;
|
||||
Layout.leftMargin: app.margins
|
||||
Layout.rightMargin: app.margins
|
||||
Layout.topMargin: app.margins
|
||||
|
||||
property bool showDetails: false
|
||||
|
||||
}
|
||||
}
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: app.margins
|
||||
|
||||
Label {
|
||||
text: qsTr("Name:")
|
||||
}
|
||||
|
||||
TextField {
|
||||
Layout.fillWidth: true
|
||||
text: root.rule.name
|
||||
onTextChanged: root.rule.name = text;
|
||||
}
|
||||
|
||||
ColorIcon {
|
||||
name: "../images/settings.svg"
|
||||
Layout.preferredHeight: app.iconSize
|
||||
Layout.preferredWidth: app.iconSize
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: ruleSettings.showDetails = !ruleSettings.showDetails
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: ruleSettings.showDetails ? implicitHeight : 0
|
||||
opacity: ruleSettings.showDetails ? 1 : 0
|
||||
Behavior on Layout.preferredHeight { NumberAnimation { duration: 200; easing.type: Easing.InOutQuad} }
|
||||
Behavior on opacity { NumberAnimation {duration: 200; easing.type: Easing.InOutQuad } }
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
text: qsTr("This rule is enabled")
|
||||
@ -140,83 +190,49 @@ Page {
|
||||
}
|
||||
}
|
||||
|
||||
ThinDivider { visible: !root.hasExitActions }
|
||||
ThinDivider { visible: !root.isStateBased }
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: app.margins
|
||||
font.pixelSize: app.mediumFont
|
||||
text: qsTr("Events triggering this rule")
|
||||
visible: !root.hasExitActions
|
||||
wrapMode: Text.WordWrap
|
||||
text: eventsRepeater.count === 0 && timeEventRepeater.count === 0 ?
|
||||
qsTr("Execute actions when something happens.") :
|
||||
qsTr("When any of these events happen...")
|
||||
visible: !root.isStateBased
|
||||
font.bold: true
|
||||
}
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: app.margins
|
||||
Layout.rightMargin: app.margins
|
||||
wrapMode: Text.WordWrap
|
||||
font.pixelSize: app.smallFont
|
||||
font.italic: true
|
||||
text: qsTr("Examples:\n• When a button is pressed...\n• When the temperature changes...\n• At 7 am...")
|
||||
visible: root.isEmpty
|
||||
}
|
||||
|
||||
|
||||
Repeater {
|
||||
id: eventsRepeater
|
||||
model: root.hasExitActions ? null : root.rule.eventDescriptors
|
||||
delegate: SwipeDelegate {
|
||||
id: eventDelegate
|
||||
delegate: EventDescriptorDelegate {
|
||||
Layout.fillWidth: true
|
||||
readonly property var eventDescriptor: root.rule.eventDescriptors.get(index)
|
||||
property var device: Engine.deviceManager.devices.getDevice(eventDescriptor.deviceId)
|
||||
property var deviceClass: device ? Engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId) : null
|
||||
property var iface: eventDescriptor.interfaceName ? Interfaces.findByName(eventDescriptor.interfaceName) : null
|
||||
property var eventType: deviceClass ? deviceClass.eventTypes.getEventType(eventDescriptor.eventTypeId)
|
||||
: iface ? iface.eventTypes.findByName(eventDescriptor.interfaceEvent) : null
|
||||
contentItem: ColumnLayout {
|
||||
Label {
|
||||
text: qsTr("%1 - %2").arg(eventDelegate.device ? eventDelegate.device.name : eventDelegate.iface.displayName).arg(eventDelegate.eventType.displayName)
|
||||
Layout.fillWidth: true
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: app.margins
|
||||
Repeater {
|
||||
model: eventDelegate.eventDescriptor.paramDescriptors
|
||||
Label {
|
||||
text: {
|
||||
var ret = eventDelegate.eventType.paramTypes.getParamType(model.id).displayName
|
||||
switch (model.operator) {
|
||||
case ParamDescriptor.ValueOperatorEquals:
|
||||
ret += " = ";
|
||||
break;
|
||||
case ParamDescriptor.ValueOperatorNotEquals:
|
||||
ret += " != ";
|
||||
break;
|
||||
case ParamDescriptor.ValueOperatorGreater:
|
||||
ret += " > ";
|
||||
break;
|
||||
case ParamDescriptor.ValueOperatorGreaterOrEqual:
|
||||
ret += " >= ";
|
||||
break;
|
||||
case ParamDescriptor.ValueOperatorLess:
|
||||
ret += " < ";
|
||||
break;
|
||||
case ParamDescriptor.ValueOperatorLessOrEqual:
|
||||
ret += " <= ";
|
||||
break;
|
||||
default:
|
||||
ret += " ? ";
|
||||
}
|
||||
eventDescriptor: root.rule.eventDescriptors.get(index)
|
||||
onRemoveEventDescriptor: root.rule.eventDescriptors.removeEventDescriptor(index)
|
||||
}
|
||||
}
|
||||
|
||||
ret += model.value
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
swipe.right: MouseArea {
|
||||
height: eventDelegate.height
|
||||
width: height
|
||||
anchors.right: parent.right
|
||||
ColorIcon {
|
||||
anchors.fill: parent
|
||||
anchors.margins: app.margins
|
||||
name: "../images/delete.svg"
|
||||
color: "red"
|
||||
}
|
||||
onClicked: root.rule.eventDescriptors.removeEventDescriptor(index)
|
||||
Repeater {
|
||||
id: timeEventRepeater
|
||||
model: root.rule.timeDescriptor.timeEventItems
|
||||
delegate: TimeEventDelegate {
|
||||
Layout.fillWidth: true
|
||||
timeEventItem: root.rule.timeDescriptor.timeEventItems.get(index)
|
||||
onRemoveTimeEventItem: {
|
||||
root.rule.timeDescriptor.timeEventItems.removeTimeEventItem(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -224,18 +240,58 @@ Page {
|
||||
Button {
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: app.margins
|
||||
text: eventsRepeater.count == 0 ? qsTr("Add an event...") : qsTr("Add another event...")
|
||||
onClicked: root.addEventDescriptor();
|
||||
visible: !root.hasExitActions
|
||||
text: eventsRepeater.count == 0 && timeEventRepeater.count === 0 ? qsTr("Configure...") : qsTr("Add another...")
|
||||
visible: !root.isStateBased
|
||||
onClicked: {
|
||||
if (root.rule.timeDescriptor.calendarItems.count > 0) {
|
||||
root.addEventDescriptor()
|
||||
} else {
|
||||
var popup = eventQuestionDialogComponent.createObject(root)
|
||||
popup.open();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ThinDivider {}
|
||||
|
||||
Label {
|
||||
text: qsTr("Conditions to be met")
|
||||
text: root.isEmpty ?
|
||||
qsTr("Do something while a condition is met.") :
|
||||
root.isEventBased ?
|
||||
qsTr("...but only if those conditions are met...") :
|
||||
qsTr("When this condition...")
|
||||
font.pixelSize: app.mediumFont
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: app.margins
|
||||
font.bold: true
|
||||
visible: {
|
||||
if (root.isEventBased) {
|
||||
if (root.rule.timeDescriptor.calendarItems.count === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (root.rule.stateEvaluator === null) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (root.rule.stateEvaluator === null && root.rule.timeDescriptor.calendarItems.count > 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
Layout.leftMargin: app.margins
|
||||
Layout.rightMargin: app.margins
|
||||
wrapMode: Text.WordWrap
|
||||
font.pixelSize: app.smallFont
|
||||
font.italic: true
|
||||
text: qsTr("Examples:\n• While I'm at home...\n• When the temperature is below 0...\n• Between 9 am and 6 pm...")
|
||||
visible: root.isEmpty
|
||||
}
|
||||
|
||||
StateEvaluatorDelegate {
|
||||
@ -244,70 +300,68 @@ Page {
|
||||
visible: root.rule.stateEvaluator !== null
|
||||
}
|
||||
|
||||
Label {
|
||||
text: root.rule.stateEvaluator === null && !root.isEventBased ?
|
||||
qsTr("When time is in...") :
|
||||
qsTr("...during this time...")
|
||||
font.pixelSize: app.mediumFont
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: app.margins
|
||||
font.bold: true
|
||||
visible: root.rule.timeDescriptor.timeEventItems.count === 0 && (root.rule.timeDescriptor.calendarItems.count > 0 || root.rule.stateEvaluator !== null)
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: root.rule.timeDescriptor.calendarItems
|
||||
delegate: CalendarItemDelegate {
|
||||
Layout.fillWidth: true
|
||||
calendarItem: root.rule.timeDescriptor.calendarItems.get(index)
|
||||
onRemoveCalendarItem: {
|
||||
root.rule.timeDescriptor.calendarItems.removeCalendarItem(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: app.margins
|
||||
text: qsTr("Add a condition")
|
||||
visible: root.rule.stateEvaluator === null
|
||||
text: root.rule.stateEvaluator === null && root.rule.timeDescriptor.calendarItems.count === 0 ?
|
||||
qsTr("Configure...") :
|
||||
qsTr("Add another...")
|
||||
visible: root.rule.timeDescriptor.timeEventItems.count === 0 || root.rule.stateEvaluator === null
|
||||
onClicked: {
|
||||
root.rule.createStateEvaluator();
|
||||
// root.editStateEvaluator()
|
||||
if (root.rule.timeDescriptor.timeEventItems.count > 0) {
|
||||
root.rule.createStateEvaluator()
|
||||
} else if (root.rule.stateEvaluator !== null) {
|
||||
root.addCalendarItem();
|
||||
} else {
|
||||
var popup = stateQuestionDialogComponent.createObject(root)
|
||||
popup.open()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ThinDivider { visible: root.actionsVisible }
|
||||
|
||||
Label {
|
||||
text: root.isStateBased ? qsTr("Active state enter actions") : qsTr("Actions to execute")
|
||||
text: root.isStateBased ?
|
||||
(root.rule.stateEvaluator === 0 ? qsTr("...come true, execute those actions:") : qsTr("...comes true, execute those actions:")) :
|
||||
qsTr("...execute those actions:")
|
||||
font.pixelSize: app.mediumFont
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: app.margins
|
||||
wrapMode: Text.WordWrap
|
||||
visible: root.actionsVisible
|
||||
font.bold: true
|
||||
}
|
||||
|
||||
Repeater {
|
||||
id: actionsRepeater
|
||||
model: root.actionsVisible ? root.rule.actions : null
|
||||
delegate: SwipeDelegate {
|
||||
id: actionDelegate
|
||||
delegate: RuleActionDelegate {
|
||||
Layout.fillWidth: true
|
||||
property var ruleAction: root.rule.actions.get(index)
|
||||
property var device: ruleAction.deviceId ? Engine.deviceManager.devices.getDevice(ruleAction.deviceId) : null
|
||||
property var iface: ruleAction.interfaceName ? Interfaces.findByName(ruleAction.interfaceName) : null
|
||||
property var deviceClass: device ? Engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId) : null
|
||||
property var actionType: deviceClass ? deviceClass.actionTypes.getActionType(ruleAction.actionTypeId)
|
||||
: iface ? iface.actionTypes.findByName(ruleAction.interfaceAction) : null
|
||||
contentItem: ColumnLayout {
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
text: qsTr("%1 - %2").arg(actionDelegate.device ? actionDelegate.device.name : actionDelegate.iface.displayName).arg(actionDelegate.actionType.displayName)
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: app.margins
|
||||
Repeater {
|
||||
model: actionDelegate.ruleAction.ruleActionParams
|
||||
Label {
|
||||
text: actionDelegate.actionType.paramTypes.getParamType(model.paramTypeId).displayName + " -> " +
|
||||
(model.eventParamTypeId.length > 0 ? qsTr("value from event") : model.value)
|
||||
font.pixelSize: app.smallFont
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
swipe.right: MouseArea {
|
||||
height: actionDelegate.height
|
||||
width: height
|
||||
anchors.right: parent.right
|
||||
ColorIcon {
|
||||
anchors.fill: parent
|
||||
anchors.margins: app.margins
|
||||
name: "../images/delete.svg"
|
||||
color: "red"
|
||||
}
|
||||
onClicked: root.rule.actions.removeRuleAction(index)
|
||||
}
|
||||
ruleAction: root.rule.actions.get(index)
|
||||
onRemoveRuleAction: root.rule.actions.removeRuleAction(index)
|
||||
}
|
||||
}
|
||||
|
||||
@ -322,56 +376,23 @@ Page {
|
||||
ThinDivider { visible: root.exitActionsVisible }
|
||||
|
||||
Label {
|
||||
text: qsTr("Active state exit actions")
|
||||
font.pixelSize: app.mediumFont
|
||||
text: qsTr("...isn't met any more, execute those actions:")
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: app.margins
|
||||
wrapMode: Text.WordWrap
|
||||
visible: root.exitActionsVisible
|
||||
font.pixelSize: app.mediumFont
|
||||
font.bold: true
|
||||
}
|
||||
|
||||
|
||||
Repeater {
|
||||
id: exitActionsRepeater
|
||||
model: root.exitActionsVisible ? root.rule.exitActions : null
|
||||
delegate: SwipeDelegate {
|
||||
id: exitActionDelegate
|
||||
delegate: RuleActionDelegate {
|
||||
Layout.fillWidth: true
|
||||
property var ruleAction: root.rule.exitActions.get(index)
|
||||
property var device: ruleAction.deviceId ? Engine.deviceManager.devices.getDevice(ruleAction.deviceId) : null
|
||||
property var iface: ruleAction.interfaceName ? Interfaces.findByName(ruleAction.interfaceName) : null
|
||||
property var deviceClass: device ? Engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId) : null
|
||||
property var actionType: deviceClass ? deviceClass.actionTypes.getActionType(ruleAction.actionTypeId)
|
||||
: iface ? iface.actionTypes.findByName(ruleAction.interfaceAction) : null
|
||||
contentItem: ColumnLayout {
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
text: qsTr("%1 - %2").arg(exitActionDelegate.device ? exitActionDelegate.device.name : exitActionDelegate.iface.displayName).arg(exitActionDelegate.actionType.displayName)
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: app.margins
|
||||
Repeater {
|
||||
model: exitActionDelegate.ruleAction.ruleActionParams
|
||||
Label {
|
||||
text: exitActionDelegate.actionType.paramTypes.getParamType(model.paramTypeId).displayName + " -> " + model.value
|
||||
font.pixelSize: app.smallFont
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
swipe.right: MouseArea {
|
||||
height: exitActionDelegate.height
|
||||
width: height
|
||||
anchors.right: parent.right
|
||||
ColorIcon {
|
||||
anchors.fill: parent
|
||||
anchors.margins: app.margins
|
||||
name: "../images/delete.svg"
|
||||
color: "red"
|
||||
}
|
||||
onClicked: root.rule.exitActions.removeRuleAction(index)
|
||||
}
|
||||
ruleAction: root.rule.exitActions.get(index)
|
||||
onClicked: root.rule.exitActions.removeRuleAction(index)
|
||||
}
|
||||
}
|
||||
|
||||
@ -389,11 +410,145 @@ Page {
|
||||
id: busyOverlay
|
||||
anchors.fill: parent
|
||||
color: "#55000000"
|
||||
opacity: 0
|
||||
opacity: root.busy ? 1 : 0
|
||||
Behavior on opacity { NumberAnimation {duration: 200 } }
|
||||
BusyIndicator {
|
||||
anchors.centerIn: parent
|
||||
running: parent.opacity > 0
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: eventQuestionDialogComponent
|
||||
MeaDialog {
|
||||
id: questionDialog
|
||||
title: qsTr("Add event...")
|
||||
standardButtons: Dialog.Cancel
|
||||
|
||||
Button {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: (app.largeFont * 2) + (app.margins * 3)
|
||||
contentItem: RowLayout {
|
||||
spacing: app.margins
|
||||
ColorIcon {
|
||||
Layout.preferredHeight: app.iconSize
|
||||
Layout.preferredWidth: height
|
||||
name: "../images/event.svg"
|
||||
color: "black"
|
||||
}
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
text: qsTr("When one of my things triggers an event")
|
||||
wrapMode: Text.WordWrap
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
}
|
||||
onClicked: {
|
||||
root.addEventDescriptor()
|
||||
questionDialog.close()
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr("or")
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: app.margins
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
|
||||
Button {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: (app.largeFont * 2) + (app.margins * 3)
|
||||
contentItem: RowLayout {
|
||||
spacing: app.margins
|
||||
ColorIcon {
|
||||
Layout.preferredHeight: app.iconSize
|
||||
Layout.preferredWidth: height
|
||||
name: "../images/alarm-clock.svg"
|
||||
color: "black"
|
||||
}
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
text: qsTr("At a particular time or date")
|
||||
wrapMode: Text.WordWrap
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
}
|
||||
onClicked: {
|
||||
root.addTimeEventItem()
|
||||
questionDialog.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: stateQuestionDialogComponent
|
||||
MeaDialog {
|
||||
id: questionDialog
|
||||
title: qsTr("Add condition...")
|
||||
standardButtons: Dialog.Cancel
|
||||
|
||||
|
||||
Button {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: (app.largeFont * 2) + (app.margins * 3)
|
||||
contentItem: RowLayout {
|
||||
spacing: app.margins
|
||||
ColorIcon {
|
||||
Layout.preferredHeight: app.iconSize
|
||||
Layout.preferredWidth: height
|
||||
name: "../images/state.svg"
|
||||
color: "black"
|
||||
}
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
text: qsTr("When one of my things is in a certain state")
|
||||
wrapMode: Text.WordWrap
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
}
|
||||
onClicked: {
|
||||
root.rule.createStateEvaluator()
|
||||
questionDialog.close()
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr("or")
|
||||
Layout.fillWidth: true
|
||||
Layout.margins: app.margins
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
|
||||
Button {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: (app.largeFont * 2) + (app.margins * 3)
|
||||
contentItem: RowLayout {
|
||||
spacing: app.margins
|
||||
ColorIcon {
|
||||
Layout.preferredHeight: app.iconSize
|
||||
Layout.preferredWidth: height
|
||||
name: "../images/clock-app-symbolic.svg"
|
||||
color: "black"
|
||||
}
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
text: qsTr("During a given time")
|
||||
wrapMode: Text.WordWrap
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
}
|
||||
onClicked: {
|
||||
root.addCalendarItem()
|
||||
questionDialog.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
301
mea/ui/magic/EditTimeEventItemPage.qml
Normal file
301
mea/ui/magic/EditTimeEventItemPage.qml
Normal file
@ -0,0 +1,301 @@
|
||||
import QtQuick 2.9
|
||||
import QtQuick.Controls 2.2
|
||||
import Qt.labs.calendar 1.0
|
||||
import QtQuick.Layouts 1.3
|
||||
import "../components"
|
||||
import Mea 1.0
|
||||
|
||||
Page {
|
||||
id: root
|
||||
|
||||
property var timeEventItem: null
|
||||
|
||||
signal done()
|
||||
signal backPressed()
|
||||
|
||||
readonly property bool isDateBased: repeatingBox.currentIndex === 0 ||
|
||||
repeatingBox.currentIndex === 5
|
||||
readonly property bool isWeekDayBased: repeatingBox.currentIndex === 3
|
||||
readonly property bool isMonthDayBased: repeatingBox.currentIndex === 4
|
||||
|
||||
header: GuhHeader {
|
||||
text: qsTr("Pick a time")
|
||||
onBackPressed: root.backPressed();
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
var date = root.isDateBased ? root.timeEventItem.dateTime : root.timeEventItem.time
|
||||
print("starting with time:", root.timeEventItem.time, root.timeEventItem.dateTime)
|
||||
if (isNaN(date)) {
|
||||
console.log("Date in rule not valid, using current datetime");
|
||||
date = new Date();
|
||||
}
|
||||
hourBox.currentIndex = date.getHours();
|
||||
minuteBox.currentIndex = date.getMinutes();
|
||||
dayBox.currentIndex = date.getDate() - 1;
|
||||
monthBox.currentIndex = date.getMonth();
|
||||
print("should set year to", date.getFullYear())
|
||||
yearBox.currentIndex = date.getFullYear() - 1970;
|
||||
}
|
||||
|
||||
function pad(num, size) {
|
||||
var s = "000000000" + num;
|
||||
return s.substr(s.length-size);
|
||||
}
|
||||
|
||||
Flickable {
|
||||
anchors.fill: parent
|
||||
contentHeight: mainColumn.implicitHeight
|
||||
|
||||
ColumnLayout {
|
||||
id: mainColumn
|
||||
anchors { left: parent.left; top: parent.top; right: parent.right }
|
||||
|
||||
GridLayout {
|
||||
columns: app.landscape ? 2 : 1
|
||||
Layout.alignment: app.landscape ? Qt.AlignHCenter : Qt.AlignLeft
|
||||
Layout.margins: app.margins
|
||||
Layout.fillWidth: !app.landscape
|
||||
|
||||
Label {
|
||||
text: qsTr("Time")
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
ComboBox {
|
||||
id: hourBox
|
||||
model: {
|
||||
if (!enabled) {
|
||||
return ["--"]
|
||||
}
|
||||
|
||||
var ret = [];
|
||||
for (var i = 0; i < 24; i++) {
|
||||
ret.push(pad(i, 2));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
enabled: repeatingBox.currentIndex !== 1
|
||||
}
|
||||
Label {
|
||||
text: ":"
|
||||
}
|
||||
ComboBox {
|
||||
id: minuteBox
|
||||
model: {
|
||||
var ret = [];
|
||||
for (var i = 0; i < 60; i++) {
|
||||
ret.push(pad(i, 2));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr("Repeat")
|
||||
Layout.topMargin: app.margins
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: app.landscape ? app.margins : 0
|
||||
|
||||
ComboBox {
|
||||
id: repeatingBox
|
||||
model: [qsTr("never"), qsTr("hourly"), qsTr("daily"), qsTr("weekly"), qsTr("monthly"), qsTr("yearly")]
|
||||
|
||||
currentIndex: {
|
||||
switch (root.timeEventItem.repeatingOption.repeatingMode) {
|
||||
case RepeatingOption.RepeatingModeNone:
|
||||
return 0;
|
||||
case RepeatingOption.RepeatingModeHourly:
|
||||
return 1;
|
||||
case RepeatingOption.RepeatingModeDaily:
|
||||
return 2;
|
||||
case RepeatingOption.RepeatingModeWeekly:
|
||||
return 3;
|
||||
case RepeatingOption.RepeatingModeMonthly:
|
||||
return 4;
|
||||
case RepeatingOption.RepeatingModeYearly:
|
||||
return 5;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Label {
|
||||
text: qsTr("Date")
|
||||
Layout.topMargin: app.margins
|
||||
visible: root.isDateBased
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillHeight: !app.landscape
|
||||
Layout.topMargin: app.landscape ? app.margins : 0
|
||||
visible: root.isDateBased
|
||||
ComboBox {
|
||||
id: dayBox
|
||||
Layout.fillWidth: true
|
||||
model: {
|
||||
var ret = [];
|
||||
for (var i = 1; i < 31; i++) {
|
||||
ret.push(pad(i, 2));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
ComboBox {
|
||||
id: monthBox
|
||||
Layout.fillWidth: true
|
||||
model: [
|
||||
qsTr("Jan"),
|
||||
qsTr("Feb"),
|
||||
qsTr("Mar"),
|
||||
qsTr("Apr"),
|
||||
qsTr("May"),
|
||||
qsTr("Jun"),
|
||||
qsTr("Jul"),
|
||||
qsTr("Aug"),
|
||||
qsTr("Sep"),
|
||||
qsTr("Oct"),
|
||||
qsTr("Nov"),
|
||||
qsTr("Dez")
|
||||
]
|
||||
}
|
||||
ComboBox {
|
||||
id: yearBox
|
||||
Layout.fillWidth: true
|
||||
model: {
|
||||
var ret = [];
|
||||
for (var i = 1970; i < 2100; i++) {
|
||||
ret.push(i);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Label {
|
||||
text: qsTr("Weekdays")
|
||||
Layout.topMargin: app.margins
|
||||
visible: root.isWeekDayBased
|
||||
}
|
||||
|
||||
DayOfWeekRow {
|
||||
id: weekDayRow
|
||||
property var weekDays: root.timeEventItem.repeatingOption.weekDays
|
||||
visible: root.isWeekDayBased
|
||||
Layout.fillWidth: !app.landscape
|
||||
Layout.topMargin: app.landscape ? app.margins : 0
|
||||
delegate: ToolButton {
|
||||
text: model.shortName
|
||||
checked: weekDayRow.weekDays.indexOf(index + 1) >= 0
|
||||
onClicked: {
|
||||
var copy = weekDayRow.weekDays
|
||||
var idx = copy.indexOf(index + 1);
|
||||
if (idx >= 0) {
|
||||
copy.splice(idx, 1);
|
||||
} else {
|
||||
copy.push(index + 1)
|
||||
}
|
||||
weekDayRow.weekDays = copy
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Label {
|
||||
text: qsTr("Day of month")
|
||||
Layout.topMargin: app.margins
|
||||
visible: root.isMonthDayBased
|
||||
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
|
||||
}
|
||||
|
||||
GridLayout {
|
||||
id: monthDayGrid
|
||||
columns: Math.sqrt(children.length)
|
||||
Layout.fillWidth: !app.landscape
|
||||
Layout.topMargin: app.landscape ? app.margins : 0
|
||||
visible: root.isMonthDayBased
|
||||
property var monthDays: root.timeEventItem.repeatingOption.monthDays
|
||||
Repeater {
|
||||
model: 31
|
||||
delegate: ToolButton {
|
||||
Layout.fillWidth: true
|
||||
checked: monthDayGrid.monthDays.indexOf(index + 1) >= 0
|
||||
text: modelData + 1
|
||||
onClicked: {
|
||||
var copy = monthDayGrid.monthDays
|
||||
var idx = copy.indexOf(index + 1);
|
||||
if (idx >= 0) {
|
||||
copy.splice(idx, 1);
|
||||
} else {
|
||||
copy.push(index + 1)
|
||||
}
|
||||
monthDayGrid.monthDays = copy
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Button {
|
||||
Layout.fillWidth: !app.landscape
|
||||
Layout.margins: app.margins
|
||||
Layout.alignment: Qt.AlignRight
|
||||
text: qsTr("OK")
|
||||
onClicked: {
|
||||
if (root.isDateBased) {
|
||||
var date = isNaN(root.timeEventItem.dateTime) ? new Date() : root.timeEventItem.dateTime
|
||||
date.setHours(hourBox.currentIndex);
|
||||
date.setMinutes(minuteBox.currentIndex);
|
||||
date.setDate(dayBox.currentIndex + 1);
|
||||
date.setMonth(monthBox.currentIndex);
|
||||
date.setYear(yearBox.currentText);
|
||||
root.timeEventItem.dateTime = date;
|
||||
} else {
|
||||
var time = isNaN(root.timeEventItem.time) ? new Date() : root.timeEventItem.time
|
||||
time.setHours(hourBox.currentIndex);
|
||||
time.setMinutes(minuteBox.currentIndex)
|
||||
root.timeEventItem.time = time;
|
||||
}
|
||||
|
||||
switch (repeatingBox.currentIndex) {
|
||||
case 0:
|
||||
root.timeEventItem.repeatingOption.repeatingMode = RepeatingOption.RepeatingModeNone;
|
||||
break;
|
||||
case 1:
|
||||
root.timeEventItem.repeatingOption.repeatingMode = RepeatingOption.RepeatingModeHourly;
|
||||
break;
|
||||
case 2:
|
||||
root.timeEventItem.repeatingOption.repeatingMode = RepeatingOption.RepeatingModeDaily;
|
||||
break;
|
||||
case 3:
|
||||
root.timeEventItem.repeatingOption.repeatingMode = RepeatingOption.RepeatingModeWeekly;
|
||||
break;
|
||||
case 4:
|
||||
root.timeEventItem.repeatingOption.repeatingMode = RepeatingOption.RepeatingModeMonthly;
|
||||
break;
|
||||
case 5:
|
||||
root.timeEventItem.repeatingOption.repeatingMode = RepeatingOption.RepeatingModeYearly;
|
||||
break;
|
||||
}
|
||||
|
||||
if (root.isWeekDayBased) {
|
||||
root.timeEventItem.repeatingOption.weekDays = weekDayRow.weekDays;
|
||||
}
|
||||
if (root.isMonthDayBased) {
|
||||
root.timeEventItem.repeatingOption.monthDays = monthDayGrid.monthDays;
|
||||
}
|
||||
|
||||
root.done()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
99
mea/ui/magic/EventDescriptorDelegate.qml
Normal file
99
mea/ui/magic/EventDescriptorDelegate.qml
Normal file
@ -0,0 +1,99 @@
|
||||
import QtQuick 2.9
|
||||
import QtQuick.Controls 2.2
|
||||
import QtQuick.Layouts 1.3
|
||||
import Mea 1.0
|
||||
import "../components"
|
||||
|
||||
SwipeDelegate {
|
||||
id: root
|
||||
implicitHeight: app.delegateHeight
|
||||
|
||||
property var eventDescriptor: null
|
||||
readonly property var device: eventDescriptor ? Engine.deviceManager.devices.getDevice(eventDescriptor.deviceId) : null
|
||||
readonly property var deviceClass: device ? Engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId) : null
|
||||
readonly property var iface: eventDescriptor.interfaceName ? Interfaces.findByName(eventDescriptor.interfaceName) : null
|
||||
readonly property var eventType: deviceClass ? deviceClass.eventTypes.getEventType(eventDescriptor.eventTypeId)
|
||||
: iface ? iface.eventTypes.findByName(eventDescriptor.interfaceEvent) : null
|
||||
|
||||
signal removeEventDescriptor()
|
||||
|
||||
contentItem: RowLayout {
|
||||
spacing: app.margins
|
||||
ColorIcon {
|
||||
Layout.preferredHeight: app.iconSize
|
||||
Layout.preferredWidth: app.iconSize
|
||||
name: "../images/event.svg"
|
||||
color: app.guhAccent
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Label {
|
||||
text: qsTr("%1 - %2").arg(root.device ? root.device.name : root.iface.displayName).arg(root.eventType.displayName)
|
||||
Layout.fillWidth: true
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
elide: Text.ElideRight
|
||||
font.pixelSize: app.smallFont
|
||||
text: {
|
||||
var ret = qsTr("anytime");
|
||||
for (var i = 0; i < root.eventDescriptor.paramDescriptors.count; i++) {
|
||||
var paramDescriptor = root.eventDescriptor.paramDescriptors.get(i)
|
||||
var operatorString;
|
||||
switch (paramDescriptor.operatorType) {
|
||||
case ParamDescriptor.ValueOperatorEquals:
|
||||
operatorString = " = ";
|
||||
break;
|
||||
case ParamDescriptor.ValueOperatorNotEquals:
|
||||
operatorString = " != ";
|
||||
break;
|
||||
case ParamDescriptor.ValueOperatorGreater:
|
||||
operatorString = " > ";
|
||||
break;
|
||||
case ParamDescriptor.ValueOperatorGreaterOrEqual:
|
||||
operatorString = " >= ";
|
||||
break;
|
||||
case ParamDescriptor.ValueOperatorLess:
|
||||
operatorString = " < ";
|
||||
break;
|
||||
case ParamDescriptor.ValueOperatorLessOrEqual:
|
||||
operatorString = " <= ";
|
||||
break;
|
||||
default:
|
||||
operatorString = " ? ";
|
||||
}
|
||||
|
||||
if (i === 0) {
|
||||
// TRANSLATORS: example: "only if temperature > 5"
|
||||
ret = qsTr("only if %1 %2 %3")
|
||||
.arg(root.eventType.paramTypes.getParamType(paramDescriptor.paramTypeId).displayName)
|
||||
.arg(operatorString)
|
||||
.arg(paramDescriptor.value)
|
||||
} else {
|
||||
// TRANSLATORS: example: "and temperature > 5"
|
||||
ret += " " + qsTr("and %1 %2 %3")
|
||||
.arg(root.eventType.paramTypes.getParamType(paramDescriptor.paramTypeId).displayName)
|
||||
.arg(operatorString)
|
||||
.arg(model.value)
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
swipe.right: MouseArea {
|
||||
height: root.height
|
||||
width: height
|
||||
anchors.right: parent.right
|
||||
ColorIcon {
|
||||
anchors.fill: parent
|
||||
anchors.margins: app.margins
|
||||
name: "../images/delete.svg"
|
||||
color: "red"
|
||||
}
|
||||
onClicked: root.removeEventDescriptor()
|
||||
}
|
||||
}
|
||||
66
mea/ui/magic/RuleActionDelegate.qml
Normal file
66
mea/ui/magic/RuleActionDelegate.qml
Normal file
@ -0,0 +1,66 @@
|
||||
import QtQuick 2.9
|
||||
import QtQuick.Controls 2.2
|
||||
import QtQuick.Layouts 1.3
|
||||
import Mea 1.0
|
||||
import "../components"
|
||||
|
||||
SwipeDelegate {
|
||||
id: root
|
||||
implicitHeight: app.delegateHeight
|
||||
property var ruleAction: null
|
||||
|
||||
property var device: ruleAction.deviceId ? Engine.deviceManager.devices.getDevice(ruleAction.deviceId) : null
|
||||
property var iface: ruleAction.interfaceName ? Interfaces.findByName(ruleAction.interfaceName) : null
|
||||
property var deviceClass: device ? Engine.deviceManager.deviceClasses.getDeviceClass(device.deviceClassId) : null
|
||||
property var actionType: deviceClass ? deviceClass.actionTypes.getActionType(ruleAction.actionTypeId)
|
||||
: iface ? iface.actionTypes.findByName(ruleAction.interfaceAction) : null
|
||||
|
||||
signal removeRuleAction()
|
||||
|
||||
contentItem: RowLayout {
|
||||
spacing: app.margins
|
||||
ColorIcon {
|
||||
Layout.preferredHeight: app.iconSize
|
||||
Layout.preferredWidth: app.iconSize
|
||||
name: "../images/action.svg"
|
||||
color: app.guhAccent
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
elide: Text.ElideRight
|
||||
text: qsTr("%1 - %2").arg(root.device ? root.device.name : root.iface.displayName).arg(root.actionType.displayName)
|
||||
}
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
elide: Text.ElideRight
|
||||
font.pixelSize: app.smallFont
|
||||
text: {
|
||||
var ret = [];
|
||||
for (var i = 0; i < root.ruleAction.ruleActionParams.count; i++) {
|
||||
var ruleActionParam = root.ruleAction.ruleActionParams.get(i)
|
||||
var paramString = qsTr("%1: %2")
|
||||
.arg(root.actionType.paramTypes.getParamType(ruleActionParam.paramTypeId).displayName)
|
||||
.arg(ruleActionParam.eventParamTypeId.length > 0 ? qsTr("value from event") : ruleActionParam.value)
|
||||
ret.push(paramString)
|
||||
}
|
||||
return ret.join(', ')
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
swipe.right: MouseArea {
|
||||
height: root.height
|
||||
width: height
|
||||
anchors.right: parent.right
|
||||
ColorIcon {
|
||||
anchors.fill: parent
|
||||
anchors.margins: app.margins
|
||||
name: "../images/delete.svg"
|
||||
color: "red"
|
||||
}
|
||||
onClicked: root.removeRuleAction()
|
||||
}
|
||||
}
|
||||
@ -96,6 +96,7 @@ Page {
|
||||
anchors.fill: parent
|
||||
anchors.margins: app.margins
|
||||
text: eventDescriptorParamsFilterModel.device.name + " - " + eventDescriptorParamsFilterModel.eventType.displayName + " - " + eventDescriptorParamsFilterModel.paramDescriptor.displayName
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
109
mea/ui/magic/TimeEventDelegate.qml
Normal file
109
mea/ui/magic/TimeEventDelegate.qml
Normal file
@ -0,0 +1,109 @@
|
||||
import QtQuick 2.9
|
||||
import QtQuick.Controls 2.2
|
||||
import QtQuick.Layouts 1.3
|
||||
import Mea 1.0
|
||||
import "../components"
|
||||
|
||||
SwipeDelegate {
|
||||
id: root
|
||||
implicitHeight: app.delegateHeight
|
||||
|
||||
property var timeEventItem: null
|
||||
|
||||
readonly property bool isDateBased: timeEventItem.repeatingOption.repeatingMode === RepeatingOption.RepeatingModeNone ||
|
||||
timeEventItem.repeatingOption.repeatingMode === RepeatingOption.RepeatingModeYearly
|
||||
|
||||
signal removeTimeEventItem();
|
||||
|
||||
contentItem: RowLayout {
|
||||
spacing: app.margins
|
||||
ColorIcon {
|
||||
Layout.preferredHeight: app.iconSize
|
||||
Layout.preferredWidth: app.iconSize
|
||||
name: "../images/alarm-clock.svg"
|
||||
color: app.guhAccent
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
elide: Text.ElideRight
|
||||
text: qsTr("At %1").arg(root.isDateBased ? Qt.formatDateTime(root.timeEventItem.dateTime) : Qt.formatTime(root.timeEventItem.time))
|
||||
}
|
||||
|
||||
Label {
|
||||
Layout.fillWidth: true
|
||||
text: qsTr("repeated %1").arg(repeatingString)
|
||||
elide: Text.ElideRight
|
||||
font.pixelSize: app.smallFont
|
||||
|
||||
property string repeatingString: {
|
||||
switch (root.timeEventItem.repeatingOption.repeatingMode) {
|
||||
case RepeatingOption.RepeatingModeNone:
|
||||
return qsTr("never");
|
||||
case RepeatingOption.RepeatingModeHourly:
|
||||
return qsTr("hourly");
|
||||
case RepeatingOption.RepeatingModeDaily:
|
||||
return qsTr("daily");
|
||||
case RepeatingOption.RepeatingModeWeekly:
|
||||
var weekdays = []
|
||||
for (var i = 0; i < root.timeEventItem.repeatingOption.weekDays.length; i++) {
|
||||
switch (root.timeEventItem.repeatingOption.weekDays[i]) {
|
||||
case 1:
|
||||
weekdays.push(qsTr("Mon"));
|
||||
break;
|
||||
case 2:
|
||||
weekdays.push(qsTr("Tue"));
|
||||
break;
|
||||
case 3:
|
||||
weekdays.push(qsTr("Wed"));
|
||||
break;
|
||||
case 4:
|
||||
weekdays.push(qsTr("Thu"));
|
||||
break;
|
||||
case 5:
|
||||
weekdays.push(qsTr("Fri"));
|
||||
break;
|
||||
case 6:
|
||||
weekdays.push(qsTr("Sat"));
|
||||
break;
|
||||
case 7:
|
||||
weekdays.push(qsTr("Sun"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return qsTr("weekly on %1").arg(weekdays.join(', '));
|
||||
case RepeatingOption.RepeatingModeMonthly:
|
||||
return qsTr("monthly on the %1").arg(root.timeEventItem.repeatingOption.monthDays.join(', '));
|
||||
case RepeatingOption.RepeatingModeYearly:
|
||||
return qsTr("every year");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
swipe.right: MouseArea {
|
||||
height: root.height
|
||||
width: height
|
||||
anchors.right: parent.right
|
||||
ColorIcon {
|
||||
anchors.fill: parent
|
||||
anchors.margins: app.margins
|
||||
name: "../images/delete.svg"
|
||||
color: "red"
|
||||
}
|
||||
onClicked: root.removeTimeEventItem()
|
||||
}
|
||||
|
||||
onClicked: {
|
||||
var page = pageStack.push(Qt.resolvedUrl("EditTimeEventItemPage.qml"), {timeEventItem: root.timeEventItem})
|
||||
page.onBackPressed.connect(function() {pageStack.pop()})
|
||||
page.onDone.connect(function() {
|
||||
pageStack.pop()
|
||||
print("timeeventItem.time is now", root.timeEventItem.time)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -30,7 +30,7 @@ Page {
|
||||
pageStack.pop();
|
||||
} else {
|
||||
console.warn("Error saving plugin params:", JSON.stringify(params))
|
||||
var dialog = errorDialog.createObject(root, {title: "Error", text: qsTr("Error saving params: ") + JSON.stringify(params.params.deviceError)});
|
||||
var dialog = errorDialog.createObject(root, {errorCode: params.params.deviceError});
|
||||
dialog.open();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user