From 85fb48bc51fed06a50b6178727fdf9e96aea4fc4 Mon Sep 17 00:00:00 2001 From: "Javier S. Pedro" Date: Sat, 13 Sep 2014 22:40:39 +0200 Subject: UI can now add some widgets around --- qml/pages/AddWidget.qml | 36 ++++++++ qml/pages/FirstPage.qml | 69 ---------------- qml/pages/MainPage.qml | 102 +++++++++++++++++++++++ qml/pages/WatchView.qml | 45 ++++++++++ qml/salmeta.qml | 4 +- qml/watch/WidgetView.qml | 93 +++++++++++++++++++++ qml/watch/add_widget.png | Bin 0 -> 2475 bytes qml/watch/faces/builtinface4.png | Bin 0 -> 1025 bytes qml/watch/faces/builtinface4.qml | 11 +++ qml/watch/main.qml | 8 -- qml/widgetview.qml | 15 ---- salmeta.pro | 18 ++-- src/availablewidgetsmodel.cpp | 65 +++++++++++++++ src/availablewidgetsmodel.h | 35 ++++++++ src/controller.cpp | 5 +- src/controller.h | 4 +- src/metawatch.cpp | 2 +- src/metawatch.h | 2 +- src/salmeta.cpp | 10 ++- src/watchviewitem.cpp | 15 ---- src/watchviewitem.h | 20 ----- src/widgetinfo.cpp | 80 +++++++++++------- src/widgetinfo.h | 43 ++++------ src/widgetinfomodel.cpp | 174 +++++++++++++++++++++++++++++++++++++++ src/widgetinfomodel.h | 46 +++++++++++ src/widgetview.cpp | 50 ----------- src/widgetview.h | 30 ------- translations/salmeta.ts | 6 +- 28 files changed, 703 insertions(+), 285 deletions(-) create mode 100644 qml/pages/AddWidget.qml delete mode 100644 qml/pages/FirstPage.qml create mode 100644 qml/pages/MainPage.qml create mode 100644 qml/pages/WatchView.qml create mode 100644 qml/watch/WidgetView.qml create mode 100644 qml/watch/add_widget.png create mode 100644 qml/watch/faces/builtinface4.png create mode 100644 qml/watch/faces/builtinface4.qml delete mode 100644 qml/watch/main.qml delete mode 100644 qml/widgetview.qml create mode 100644 src/availablewidgetsmodel.cpp create mode 100644 src/availablewidgetsmodel.h delete mode 100644 src/watchviewitem.cpp delete mode 100644 src/watchviewitem.h create mode 100644 src/widgetinfomodel.cpp create mode 100644 src/widgetinfomodel.h delete mode 100644 src/widgetview.cpp delete mode 100644 src/widgetview.h diff --git a/qml/pages/AddWidget.qml b/qml/pages/AddWidget.qml new file mode 100644 index 0000000..50bf63d --- /dev/null +++ b/qml/pages/AddWidget.qml @@ -0,0 +1,36 @@ +import QtQuick 2.0 +import Sailfish.Silica 1.0 +import com.javispedro.salmeta 1.0 + +Page { + id: page + + property int addToPage + property int addToPos + + SilicaListView { + id: allWidgetsListView + anchors.fill: parent + + model: allWidgets + + header: PageHeader { + title: "Add widget" + } + + delegate : BackgroundItem { + contentHeight: Theme.itemSizeMedium + + Label { + text: url + truncationMode: TruncationMode.Elide + color: highlighted ? Theme.highlightColor : Theme.primaryColor + } + + onClicked: { + curWidgets.addWidget(url, addToPage, addToPos, size); + pageStack.pop(); + } + } + } +} diff --git a/qml/pages/FirstPage.qml b/qml/pages/FirstPage.qml deleted file mode 100644 index b86029e..0000000 --- a/qml/pages/FirstPage.qml +++ /dev/null @@ -1,69 +0,0 @@ -import QtQuick 2.0 -import Sailfish.Silica 1.0 -import Sailfish.Bluetooth 1.0 -import org.nemomobile.configuration 1.0 -import com.javispedro.salmeta 1.0 - -Page { - id: page - - ConfigurationValue { - id: deviceAddress - key: settingsPrefix + "/address" - defaultValue: "Select" - } - - SilicaFlickable { - anchors.fill: parent - - PullDownMenu { - MenuItem { - text: qsTr("Not done yet") - } - } - - contentHeight: column.height - - Column { - id: column - width: page.width - spacing: Theme.paddingLarge - - PageHeader { - title: "Salmeta" - } - - SectionHeader { - text: qsTr("Device settings"); - } - - ValueButton { - x: Theme.paddingLarge - label: "Device" - value: deviceAddress.value - - onClicked: { - var dialog = pageStack.push("Sailfish.Bluetooth.BluetoothDevicePickerDialog"); - - dialog.selectedDeviceChanged.connect(function() { - if (dialog.selectedDevice != "") { - deviceAddress.value = dialog.selectedDevice - } - }); - } - } - - SectionHeader { - text: qsTr("Widgets"); - } - - WatchView { - anchors.horizontalCenter: parent.horizontalCenter - width: 96 * 4 - height: 96 * 4 - } - } - } -} - - diff --git a/qml/pages/MainPage.qml b/qml/pages/MainPage.qml new file mode 100644 index 0000000..5448754 --- /dev/null +++ b/qml/pages/MainPage.qml @@ -0,0 +1,102 @@ +import QtQuick 2.0 +import Sailfish.Silica 1.0 +import Sailfish.Bluetooth 1.0 +import org.nemomobile.configuration 1.0 + +Page { + id: page + + ConfigurationValue { + id: deviceAddress + key: curSettingsPrefix + "/address" + defaultValue: "Select" + } + + SilicaFlickable { + anchors.fill: parent + + PullDownMenu { + MenuItem { + text: qsTr("Not done yet") + } + } + + contentHeight: column.height + + Column { + id: column + width: page.width + spacing: Theme.paddingLarge + + PageHeader { + title: "Salmeta" + } + + SectionHeader { + text: qsTr("Device settings"); + } + + ValueButton { + x: Theme.paddingLarge + label: "Device" + value: deviceAddress.value + + onClicked: { + var dialog = pageStack.push("Sailfish.Bluetooth.BluetoothDevicePickerDialog"); + + dialog.selectedDeviceChanged.connect(function() { + if (dialog.selectedDevice !== "") { + deviceAddress.value = dialog.selectedDevice + } + }); + } + } + + SectionHeader { + text: qsTr("Widgets"); + } + + Item { + width: 96 * 4 + height: 96 * 4 + anchors.horizontalCenter: parent.horizontalCenter + + WatchView { + id: watchView + anchors.centerIn: parent + scale: 4 + } + } + + Row { + anchors.horizontalCenter: parent.horizontalCenter + spacing: 8 + + Repeater { + model: 4 + + Rectangle { + // TODO These should be GlassItem. + width: 16 + height: 16 + radius: 8 + + color: "white" + opacity: watchView.curPage == index ? 0.9 : 0.3 + } + } + } + + SectionHeader { + text: qsTr("Notifications"); + } + + Label { + x: Theme.paddingLarge + text: "TODO" + } + } + } +} + + diff --git a/qml/pages/WatchView.qml b/qml/pages/WatchView.qml new file mode 100644 index 0000000..e738f4e --- /dev/null +++ b/qml/pages/WatchView.qml @@ -0,0 +1,45 @@ +import QtQuick 2.0 +import "../watch" + +Flickable { + id: watchView + width: 96 + height: 96 + clip: true + flickableDirection: Flickable.HorizontalFlick + + property int curPage: 0 + + WidgetView { + id: widgetView + model: curWidgets + editMode: true + onEmptyWidgetClicked: { + pageStack.push(Qt.resolvedUrl("AddWidget.qml"), { + 'addToPage': page, + 'addToPos': pos + }); + } + } + + contentWidth: widgetView.width + contentHeight: widgetView.height + + NumberAnimation { + id: pivotAnim + targets: watchView + property: "contentX" + to: curPage * watchView.width + duration: 100 + easing.type: Easing.InOutQuad + } + + onMovementStarted: { + pivotAnim.stop() + } + + onMovementEnded: { + curPage = Math.round(watchView.contentX / watchView.width) + pivotAnim.start() + } +} diff --git a/qml/salmeta.qml b/qml/salmeta.qml index bb031a4..e2f2896 100644 --- a/qml/salmeta.qml +++ b/qml/salmeta.qml @@ -34,8 +34,6 @@ import "pages" ApplicationWindow { - initialPage: Component { FirstPage { } } + initialPage: Component { MainPage { } } cover: Qt.resolvedUrl("cover/CoverPage.qml") } - - diff --git a/qml/watch/WidgetView.qml b/qml/watch/WidgetView.qml new file mode 100644 index 0000000..9e64fac --- /dev/null +++ b/qml/watch/WidgetView.qml @@ -0,0 +1,93 @@ +import QtQuick 2.0 +import com.javispedro.salmeta 1.0 + +Rectangle { + id: view + width: 96*4 + height: 96 + + color: "white"; + + property alias model: rep.model + property bool editMode: false + + signal emptyWidgetClicked(int page, int pos) + + Grid { + id: editGrid + anchors.fill: parent + columns: 2 * 4 + rows: 2 + visible: editMode + + function _calculatePagePosFromIndex(index) { + switch (index) { + case 0: return [0, 0]; + case 1: return [0, 1]; + case 8: return [0, 2]; + case 9: return [0, 3]; + case 2: return [1, 0]; + case 3: return [1, 1]; + case 10: return [1, 2]; + case 11: return [1, 3]; + case 4: return [2, 0]; + case 5: return [2, 1]; + case 12: return [2, 2]; + case 13: return [2, 3]; + case 6: return [3, 0]; + case 7: return [3, 1]; + case 14: return [3, 2]; + case 15: return [3, 3]; + } + } + + Repeater { + model: 16 + Rectangle { + width: 96 / 2 + height: 96 / 2 + Image { + anchors.centerIn: parent + source: "add_widget.png" + } + MouseArea { + anchors.fill: parent + onClicked: { + var pagePos = editGrid._calculatePagePosFromIndex(index); + view.emptyWidgetClicked(pagePos[0], pagePos[1]); + } + } + } + } + } + + Repeater { + id: rep + + Item { + id: widgetItem + + x: (model.page * 96) + (model.position === WidgetInfo.PosNE || model.position === WidgetInfo.PosSE ? 96 / 2 : 0) + y: (model.position === WidgetInfo.PosSE || model.position === WidgetInfo.PosSW ? 96 / 2 : 0) + width: model.size === WidgetInfo.Size2QHorizontal | model.size === WidgetInfo.Size4Q ? 96 : 96 / 2 + height: model.size === WidgetInfo.Size2QVertical | model.size === WidgetInfo.Size4Q ? 96 : 96 / 2 + + visible: widgetLoader.status === Loader.Ready; + + Loader { + id: widgetLoader + anchors.fill: parent + source: url + } + + MouseArea { + anchors.fill: parent + enabled: editMode + + onClicked: { + curWidgets.removeWidget(index); + } + } + } + } +} diff --git a/qml/watch/add_widget.png b/qml/watch/add_widget.png new file mode 100644 index 0000000..97f5bc4 Binary files /dev/null and b/qml/watch/add_widget.png differ diff --git a/qml/watch/faces/builtinface4.png b/qml/watch/faces/builtinface4.png new file mode 100644 index 0000000..eb05c95 Binary files /dev/null and b/qml/watch/faces/builtinface4.png differ diff --git a/qml/watch/faces/builtinface4.qml b/qml/watch/faces/builtinface4.qml new file mode 100644 index 0000000..f9eff50 --- /dev/null +++ b/qml/watch/faces/builtinface4.qml @@ -0,0 +1,11 @@ +import QtQuick 2.0 + +Rectangle { + width: 96 + height: 96 + + Image { + anchors.fill: parent + source: "builtinface4.png" + } +} diff --git a/qml/watch/main.qml b/qml/watch/main.qml deleted file mode 100644 index 200a8b0..0000000 --- a/qml/watch/main.qml +++ /dev/null @@ -1,8 +0,0 @@ -import QtQuick 2.0 - -Rectangle { - width: 96 - height: 96 - - color: "white" -} diff --git a/qml/widgetview.qml b/qml/widgetview.qml deleted file mode 100644 index 077431d..0000000 --- a/qml/widgetview.qml +++ /dev/null @@ -1,15 +0,0 @@ -import QtQuick 2.0 - -Rectangle { - width: 96*4 - height: 96 - - color: Qt.rgba(0, 0, 0, 1); - - Repeater { - model: 16 - Loader { - - } - } -} diff --git a/salmeta.pro b/salmeta.pro index 740bb53..acc91c4 100644 --- a/salmeta.pro +++ b/salmeta.pro @@ -16,9 +16,9 @@ SOURCES += src/salmeta.cpp \ src/metawatchbletransport.cpp \ src/reconnecttimer.cpp \ src/notificationmonitor.cpp \ - src/widgetview.cpp \ src/widgetinfo.cpp \ - src/watchviewitem.cpp + src/widgetinfomodel.cpp \ + src/availablewidgetsmodel.cpp HEADERS += \ src/controller.h \ @@ -27,22 +27,24 @@ HEADERS += \ src/metawatchbletransport.h \ src/reconnecttimer.h \ src/notificationmonitor.h \ - src/widgetview.h \ src/widgetinfo.h \ - src/watchviewitem.h + src/widgetinfomodel.h \ + src/availablewidgetsmodel.h OTHER_FILES += qml/salmeta.qml \ qml/cover/CoverPage.qml \ - qml/pages/FirstPage.qml \ rpm/salmeta.changes.in \ rpm/salmeta.spec \ rpm/salmeta.yaml \ translations/*.ts \ salmeta.desktop \ salmeta.png \ - qml/watch/main.qml \ - qml/widgetview.qml \ - salmeta.service + salmeta.service \ + qml/pages/MainPage.qml \ + qml/watch/WidgetView.qml \ + qml/pages/WatchView.qml qml/watch/add_widget.png \ + qml/watch/faces/builtinface4.qml qml/watch/faces/builtinface4.png \ + qml/pages/AddWidget.qml # to disable building translations every time, comment out the # following CONFIG line diff --git a/src/availablewidgetsmodel.cpp b/src/availablewidgetsmodel.cpp new file mode 100644 index 0000000..02ca746 --- /dev/null +++ b/src/availablewidgetsmodel.cpp @@ -0,0 +1,65 @@ +#include + +#include "availablewidgetsmodel.h" + +AvailableWidgetsModel::AvailableWidgetsModel(QObject *parent) : + QAbstractListModel(parent) +{ + reload(); +} + +QHash AvailableWidgetsModel::roleNames() const +{ + QHash roles; + + roles[UrlRole] = "url"; + roles[SizeRole] = "size"; + + return roles; +} + +int AvailableWidgetsModel::rowCount(const QModelIndex &parent) const +{ + if (parent.isValid()) return 0; + return _widgets.size(); +} + +QVariant AvailableWidgetsModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) return QVariant(); + const int row = index.row(); + if (row < 0 || row >= _widgets.size()) return QVariant(); + + switch (role) { + case UrlRole: + return QVariant::fromValue(_widgets[row].url()); + case DescriptionRole: + return QVariant::fromValue(_widgets[row].description()); + case SizeRole: + return QVariant::fromValue(_widgets[row].size()); + default: + qWarning() << "Unknown role:" << role; + return QVariant(); + } +} + +void AvailableWidgetsModel::reload() +{ + beginResetModel(); + _widgets.clear(); + + // Load builtin widgets + WidgetInfo info; + + info.setUrl(SailfishApp::pathTo("qml/watch/faces/builtinface4.qml")); + info.setDescription("Watchface #4"); + info.setSize(WidgetInfo::Size4Q); + _widgets.append(info); + + info.setUrl(SailfishApp::pathTo("qml/watch/faces/builtinface4.qml")); + info.setDescription("Watchface #4"); + info.setSize(WidgetInfo::Size4Q); + _widgets.append(info); + + endResetModel(); +} diff --git a/src/availablewidgetsmodel.h b/src/availablewidgetsmodel.h new file mode 100644 index 0000000..86114d9 --- /dev/null +++ b/src/availablewidgetsmodel.h @@ -0,0 +1,35 @@ +#ifndef AVAILABLEWIDGETSMODEL_H +#define AVAILABLEWIDGETSMODEL_H + +#include +#include + +#include "widgetinfo.h" + +class AvailableWidgetsModel : public QAbstractListModel +{ + Q_OBJECT +public: + explicit AvailableWidgetsModel(QObject *parent = 0); + + enum Roles { + UrlRole = Qt::UserRole, + DescriptionRole, + SizeRole + }; + + QHash roleNames() const; + int rowCount(const QModelIndex &parent) const; + QVariant data(const QModelIndex &index, int role) const; + +signals: + +public slots: + void reload(); + +private: + QFileSystemWatcher *_watcher; + QVector _widgets; +}; + +#endif // AVAILABLEWIDGETSMODEL_H diff --git a/src/controller.cpp b/src/controller.cpp index 047ad96..9d1961c 100644 --- a/src/controller.cpp +++ b/src/controller.cpp @@ -13,7 +13,7 @@ Controller::Controller(const QString &settingsPrefix, QQuickView *view, QObject _settings(new MDConfGroup(this)), _metawatch(0), _reconnect(new ReconnectTimer(this)), - _view(new WidgetView(settingsPrefix, view, this)), + _widgets(new WidgetInfoModel(settingsPrefix, this)), _batteryCharge(0), _batteryCharging(false) { _settings->setPath(settingsPrefix); @@ -25,6 +25,7 @@ Controller::Controller(const QString &settingsPrefix, QQuickView *view, QObject connect(_metawatch, &MetaWatch::disconnected, _reconnect, &ReconnectTimer::scheduleNextAttempt); connect(_metawatch, &MetaWatch::batteryStatus, this, &Controller::handleMetaWatchBatteryStatus); connect(_reconnect, &ReconnectTimer::tryReconnect, _metawatch, &MetaWatch::connectDevice); + connect(_recc) _reconnect->scheduleNextAttempt(); @@ -69,7 +70,7 @@ void Controller::handleMetaWatchConnected() _metawatch->setDateTime(QDateTime::currentDateTime()); _metawatch->updateLcdDisplay(); - _metawatch->updateWidgetList(_view->widgets()); + // TODO _metawatch->updateWidgetList(_view->widgets()); } void Controller::handleMetaWatchBatteryStatus(bool charging, int charge) diff --git a/src/controller.h b/src/controller.h index d7f2349..3570ff4 100644 --- a/src/controller.h +++ b/src/controller.h @@ -6,8 +6,8 @@ #include #include "metawatch.h" -#include "widgetview.h" #include "reconnecttimer.h" +#include "widgetinfomodel.h" class Controller : public QObject { @@ -43,7 +43,7 @@ private: MetaWatch *_metawatch; ReconnectTimer *_reconnect; - WidgetView *_view; + WidgetInfoModel *_widgets; // Watch status int _batteryCharge; diff --git a/src/metawatch.cpp b/src/metawatch.cpp index a27d0ec..b1ea8af 100644 --- a/src/metawatch.cpp +++ b/src/metawatch.cpp @@ -63,7 +63,7 @@ void MetaWatch::updateLcdDisplay() _transport->sendMessage(MessageUpdateLcdDisplay, 0x80, QByteArray()); } -void MetaWatch::updateWidgetList(const QList &widgets) +void MetaWatch::updateWidgetList(const QList &widgets) { int num_widgets = 0; diff --git a/src/metawatch.h b/src/metawatch.h index dd02bf4..9068c08 100644 --- a/src/metawatch.h +++ b/src/metawatch.h @@ -75,7 +75,7 @@ public: void updateDeviceType(); void updateBatteryStatus(); void updateLcdDisplay(); // TODO: More overloads - void updateWidgetList(const QList& widgets); + void updateWidgetList(const QList& widgets); signals: void connected(); diff --git a/src/salmeta.cpp b/src/salmeta.cpp index f13cd64..46e4e89 100644 --- a/src/salmeta.cpp +++ b/src/salmeta.cpp @@ -2,7 +2,8 @@ #include #include "controller.h" -#include "watchviewitem.h" +#include "widgetinfomodel.h" +#include "availablewidgetsmodel.h" static bool launch_daemon = false; static QString settings_key_prefix("/apps/salmeta/watch0"); @@ -25,7 +26,8 @@ int main(int argc, char *argv[]) ++it; } - qmlRegisterType("com.javispedro.salmeta", 1, 0, "WatchView"); + qmlRegisterUncreatableType("com.javispedro.salmeta", 1, 0, "WidgetInfo", + "Use the models, not this"); if (launch_daemon) { qDebug() << "Starting salmeta (daemon) with settings from" << settings_key_prefix; @@ -33,7 +35,9 @@ int main(int argc, char *argv[]) new Controller(settings_key_prefix, SailfishApp::createView()); } else { QQuickView *view = SailfishApp::createView(); - view->rootContext()->setContextProperty("settingsPrefix", settings_key_prefix); + view->rootContext()->setContextProperty("curSettingsPrefix", settings_key_prefix); + view->rootContext()->setContextProperty("curWidgets", new WidgetInfoModel(settings_key_prefix)); + view->rootContext()->setContextProperty("allWidgets", new AvailableWidgetsModel); view->setSource(SailfishApp::pathTo("qml/salmeta.qml")); view->show(); } diff --git a/src/watchviewitem.cpp b/src/watchviewitem.cpp deleted file mode 100644 index dbd4e8a..0000000 --- a/src/watchviewitem.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include -#include - -#include "watchviewitem.h" - -WatchViewItem::WatchViewItem(QQuickItem *parent) : - QQuickPaintedItem(parent) -{ - setFillColor(Qt::white); -} - -void WatchViewItem::paint(QPainter *painter) -{ - -} diff --git a/src/watchviewitem.h b/src/watchviewitem.h deleted file mode 100644 index 5219852..0000000 --- a/src/watchviewitem.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef WATCHVIEWITEM_H -#define WATCHVIEWITEM_H - -#include - -class WatchViewItem : public QQuickPaintedItem -{ - Q_OBJECT -public: - explicit WatchViewItem(QQuickItem *parent = 0); - - void paint(QPainter *painter); - -signals: - -public slots: - -}; - -#endif // WATCHVIEWITEM_H diff --git a/src/widgetinfo.cpp b/src/widgetinfo.cpp index 477b61c..d23da8f 100644 --- a/src/widgetinfo.cpp +++ b/src/widgetinfo.cpp @@ -1,83 +1,99 @@ #include "widgetinfo.h" -WidgetInfo::WidgetInfo(QObject *parent) - : QObject(parent) +struct WidgetInfoData : public QSharedData { + QUrl url; + QString desc; + bool invert; + short page; + WidgetInfo::WidgetSize size; + WidgetInfo::WidgetPosition pos; +}; +WidgetInfo::WidgetInfo() + : d(new WidgetInfoData) +{ +} + +WidgetInfo::WidgetInfo(const WidgetInfo &other) + : d(other.d) +{ +} + +WidgetInfo::~WidgetInfo() +{ +} + +WidgetInfo& WidgetInfo::operator =(const WidgetInfo &other) +{ + if (this != &other) { + d = other.d; + } + + return *this; } bool WidgetInfo::valid() const { - return !_url.isEmpty(); + return !d->url.isEmpty(); } QUrl WidgetInfo::url() const { - return _url; + return d->url; } void WidgetInfo::setUrl(const QUrl &url) { - if (url != _url) { - const bool cur_valid = valid(); + d->url = url; +} - _url = url; - emit urlChanged(); +QString WidgetInfo::description() const +{ + return d->desc; +} - if (cur_valid != valid()) { - emit validChanged(); - } - } +void WidgetInfo::setDescription(const QString &desc) +{ + d->desc = desc; } bool WidgetInfo::invert() const { - return _invert; + return d->invert; } void WidgetInfo::setInvert(bool invert) { - if (invert != _invert) { - _invert = invert; - emit invertChanged(); - } + d->invert = invert; } int WidgetInfo::page() const { - return _page; + return d->page; } void WidgetInfo::setPage(int page) { - if (page != _page) { - _page = page; - emit pageChanged(); - } + d->page = page; } WidgetInfo::WidgetSize WidgetInfo::size() const { - return _size; + return d->size; } void WidgetInfo::setSize(const WidgetSize &size) { - if (size != _size) { - _size = size; - emit sizeChanged(); - } + d->size = size; } WidgetInfo::WidgetPosition WidgetInfo::position() const { - return _pos; + return d->pos; } void WidgetInfo::setPosition(const WidgetPosition &pos) { - if (pos != _pos) { - _pos = pos; - emit positionChanged(); - } + d->pos = pos; } diff --git a/src/widgetinfo.h b/src/widgetinfo.h index 06a6149..51d617b 100644 --- a/src/widgetinfo.h +++ b/src/widgetinfo.h @@ -1,23 +1,23 @@ #ifndef WIDGETINFO_H #define WIDGETINFO_H -#include +#include +#include #include -class WidgetInfo : public QObject +class WidgetInfoData; + +class WidgetInfo { - Q_OBJECT + Q_GADGET Q_ENUMS(WidgetSize WidgetPosition) - Q_PROPERTY(bool valid READ valid NOTIFY validChanged) - Q_PROPERTY(QUrl url READ url WRITE setUrl NOTIFY urlChanged) - Q_PROPERTY(bool invert READ invert WRITE setInvert NOTIFY invertChanged) - Q_PROPERTY(int page READ page WRITE setPage NOTIFY pageChanged) - Q_PROPERTY(WidgetSize size READ size WRITE setSize NOTIFY sizeChanged) - Q_PROPERTY(WidgetPosition position READ position WRITE setPosition NOTIFY positionChanged) - public: - explicit WidgetInfo(QObject *parent = 0); + WidgetInfo(); + WidgetInfo(const WidgetInfo &other); + ~WidgetInfo(); + + WidgetInfo& operator=(const WidgetInfo &other); enum WidgetSize { @@ -40,6 +40,9 @@ public: QUrl url() const; void setUrl(const QUrl &url); + QString description() const; + void setDescription(const QString &desc); + bool invert() const; void setInvert(bool invert); @@ -52,21 +55,11 @@ public: WidgetPosition position() const; void setPosition(const WidgetPosition &pos); -signals: - void validChanged(); - void urlChanged(); - void invertChanged(); - void pageChanged(); - void sizeChanged(); - void positionChanged(); - private: - QUrl _url; - bool _invert; - short _page; - WidgetSize _size; - WidgetPosition _pos; - + QSharedDataPointer d; }; +Q_DECLARE_METATYPE(WidgetInfo::WidgetSize) +Q_DECLARE_METATYPE(WidgetInfo::WidgetPosition) + #endif // WIDGETINFO_H diff --git a/src/widgetinfomodel.cpp b/src/widgetinfomodel.cpp new file mode 100644 index 0000000..6c4d5d2 --- /dev/null +++ b/src/widgetinfomodel.cpp @@ -0,0 +1,174 @@ +#include +#include +#include "widgetinfomodel.h" + +namespace +{ + +inline QString get_widget_dconf_base(int index) +{ + return QString("widget%1_").arg(index); +} + +} + +WidgetInfoModel::WidgetInfoModel(const QString &settingsPrefix, QObject *parent) : + QAbstractListModel(parent), + _settings(new MDConfGroup(this)) +{ + _settings->setPath(settingsPrefix); + connect(_settings, &MDConfGroup::valueChanged, + this, &WidgetInfoModel::handleSettingChanged); + reload(); +} + +QHash WidgetInfoModel::roleNames() const +{ + QHash roles; + + roles[UrlRole] = "url"; + roles[InvertRole] = "invert"; + roles[PageRole] = "page"; + roles[SizeRole] = "size"; + roles[PositionRole] = "position"; + + return roles; +} + +int WidgetInfoModel::rowCount(const QModelIndex &parent) const +{ + if (parent.isValid()) return 0; + return _widgets.size(); +} + +QVariant WidgetInfoModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) return QVariant(); + const int row = index.row(); + if (row < 0 || row >= _widgets.size()) return QVariant(); + + switch (role) { + case UrlRole: + return QVariant::fromValue(_widgets[row].url()); + case InvertRole: + return QVariant::fromValue(_widgets[row].invert()); + case PageRole: + return QVariant::fromValue(_widgets[row].page()); + case SizeRole: + return QVariant::fromValue(_widgets[row].size()); + case PositionRole: + return QVariant::fromValue(_widgets[row].position()); + default: + qWarning() << "Unknown role:" << role; + return QVariant(); + } +} + +void WidgetInfoModel::reload() +{ + beginResetModel(); + _widgets.resize(16); + + for (int i = 0; i < _widgets.size(); i++) { + WidgetInfo &info = _widgets[i]; + const QString base = get_widget_dconf_base(i); + + info.setInvert(_settings->value(base + "invert").toBool()); + info.setPage(_settings->value(base + "page").toInt()); + info.setSize(static_cast(_settings->value(base + "size").toInt())); + info.setPosition(static_cast(_settings->value(base + "position").toInt())); + info.setUrl(_settings->value(base + "url").toUrl()); + } + + endResetModel(); +} + +int WidgetInfoModel::addWidget(const QUrl &url, int page, WidgetInfo::WidgetPosition pos, WidgetInfo::WidgetSize size) +{ + int slot = findEmptySlot(); + if (slot == -1) { + qWarning() << "No empty slots!"; // This shouldn't happen + return slot; + } + + qDebug() << "Adding widget" << url << page << pos << size; + + const QString base = get_widget_dconf_base(slot); + + _settings->setValue(base + "invert", QVariant::fromValue(false)); + _settings->setValue(base + "page", QVariant::fromValue(page)); + _settings->setValue(base + "size", QVariant::fromValue(size)); + _settings->setValue(base + "position", QVariant::fromValue(pos)); + _settings->setValue(base + "url", QVariant::fromValue(url)); + + // MDConf watcher will update the model. + + return slot; +} + +void WidgetInfoModel::removeWidget(int widgetId) +{ + const QString base = get_widget_dconf_base(widgetId); + + _settings->setValue(base + "url", QVariant()); + _settings->setValue(base + "invert", QVariant()); + _settings->setValue(base + "page", QVariant()); + _settings->setValue(base + "size", QVariant()); + _settings->setValue(base + "position", QVariant()); +} + +int WidgetInfoModel::findEmptySlot() +{ + for (int i = 0; i < _widgets.size(); i++) { + if (_widgets[i].url().isEmpty()) { + return i; + } + } + + return -1; +} + +void WidgetInfoModel::handleSettingChanged(const QString &key) +{ + static const QString widgetPrefix("widget"); + if (key.startsWith(widgetPrefix)) { + QStringList parts = key.split('_'); + if (parts.size() == 2) { + bool ok = false; + int slot = parts[0].mid(widgetPrefix.length()).toInt(&ok); + if (!ok || slot < 0 || slot >= _widgets.size()) { + qWarning() << "Invalid widget number:" << key; + } + + WidgetInfo &info = _widgets[slot]; + const QString &role = parts[1]; + QVector roles; + + if (role == "url") { + info.setUrl(_settings->value(key).toUrl()); + roles << UrlRole; + } else if (role == "invert") { + info.setInvert(_settings->value(key).toBool()); + roles << InvertRole; + } else if (role == "page") { + info.setPage(_settings->value(key).toInt()); + roles << PageRole; + } else if (role == "size") { + info.setSize(static_cast(_settings->value(key).toInt())); + roles << SizeRole; + } else if (role == "position") { + info.setPosition(static_cast(_settings->value(key).toInt())); + roles << PositionRole; + } else { + qWarning() << "Unknown widget key changed:" << key; + return; + } + + const QModelIndex index = createIndex(slot, 0); + qDebug() << "Data changed" << slot << roles.at(0); + emit dataChanged(index, index, roles); + } else { + qWarning() << "Unknown widget key changed:" << key; + } + } +} diff --git a/src/widgetinfomodel.h b/src/widgetinfomodel.h new file mode 100644 index 0000000..6b30a91 --- /dev/null +++ b/src/widgetinfomodel.h @@ -0,0 +1,46 @@ +#ifndef WIDGETINFOMODEL_H +#define WIDGETINFOMODEL_H + +#include +#include + +#include "widgetinfo.h" + +class WidgetInfoModel : public QAbstractListModel +{ + Q_OBJECT + +public: + explicit WidgetInfoModel(const QString &settingsPrefix, QObject *parent = 0); + + enum Roles { + UrlRole = Qt::UserRole, + InvertRole, + PageRole, + SizeRole, + PositionRole + }; + + QHash roleNames() const; + int rowCount(const QModelIndex &parent) const; + QVariant data(const QModelIndex &index, int role) const; + +signals: + +public slots: + void reload(); + int addWidget(const QUrl &url, int page, WidgetInfo::WidgetPosition pos, WidgetInfo::WidgetSize size); + void removeWidget(int widgetId); + +private: + int findEmptySlot(); + +private slots: + void handleSettingChanged(const QString &key); + +private: + MDConfGroup *_settings; + QVector _widgets; +}; + +#endif // WIDGETINFOMODEL_H diff --git a/src/widgetview.cpp b/src/widgetview.cpp deleted file mode 100644 index e5bf21e..0000000 --- a/src/widgetview.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include -#include - -#include "widgetview.h" - -#define NUM_WIDGETS 16 - -WidgetView::WidgetView(const QString &settingsPrefix, QQuickView *view, QObject *parent) - : QObject(parent), - _settings(new MDConfGroup(this)), - _view(view) -{ - _settings->setPath(settingsPrefix); - - if (!_view) { - _view = new QQuickView; - } - - for (int w = 0; w < NUM_WIDGETS; w++) { - WidgetInfo *info = new WidgetInfo(this); - - _widgets.append(info); - _widgetObjects.append(static_cast(info)); - } - - reload(); - - _view->setResizeMode(QQuickView::SizeViewToRootObject); - _view->setSource(SailfishApp::pathTo("qml/widgetview.qml")); - _view->rootContext()->setContextProperty("widgets", QVariant::fromValue(_widgetObjects)); -} - -QList WidgetView::widgets() -{ - return _widgets; -} - -void WidgetView::reload() -{ - for (int w = 0; w < _widgets.size(); w++) { - WidgetInfo *widget = _widgets[w]; - QString base = QString("widget%1/").arg(w); - - widget->setInvert(_settings->value(base + "invert").toBool()); - widget->setPage(_settings->value(base + "page").toInt()); - widget->setSize(static_cast(_settings->value(base + "size").toInt())); - widget->setPosition(static_cast(_settings->value(base + "position").toInt())); - widget->setUrl(_settings->value(base + "url").toUrl()); - } -} diff --git a/src/widgetview.h b/src/widgetview.h deleted file mode 100644 index 6ce294d..0000000 --- a/src/widgetview.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef WIDGETVIEW_H -#define WIDGETVIEW_H - -#include -#include -#include - -#include - -#include "widgetinfo.h" - -class WidgetView : public QObject -{ - Q_OBJECT -public: - WidgetView(const QString &settingsPrefix, QQuickView *view, QObject *parent = 0); - - QList widgets(); - -public slots: - void reload(); - -private: - MDConfGroup *_settings; - QQuickView *_view; - QList _widgets; - QObjectList _widgetObjects; -}; - -#endif // WIDGETVIEW_H diff --git a/translations/salmeta.ts b/translations/salmeta.ts index 09129a8..79cf7af 100644 --- a/translations/salmeta.ts +++ b/translations/salmeta.ts @@ -2,7 +2,7 @@ - FirstPage + MainPage Not done yet @@ -15,5 +15,9 @@ Widgets + + Notifications + + -- cgit v1.2.3