From 03e8aabf1754f5061f207d2c9c082ba6199db0e5 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Fri, 2 Mar 2018 12:00:54 +0100 Subject: Visualize that a folder has new mails. We listen for new mail notifications, and highlight the folder accordingly. --- components/kube/qml/Kube.qml | 9 ++++++- framework/qml/FolderListView.qml | 34 ++++++++++++++++++++------ framework/qml/TreeView.qml | 33 +++++-------------------- framework/src/domain/folderlistmodel.cpp | 41 ++++++++++++++++++++++++++++++++ framework/src/domain/folderlistmodel.h | 8 ++++++- framework/src/sinkfabric.cpp | 5 ++++ 6 files changed, 94 insertions(+), 36 deletions(-) diff --git a/components/kube/qml/Kube.qml b/components/kube/qml/Kube.qml index 3a970733..eba70c70 100644 --- a/components/kube/qml/Kube.qml +++ b/components/kube/qml/Kube.qml @@ -100,7 +100,14 @@ Controls2.ApplicationWindow { Shortcut { id: syncShortcut sequence: StandardKey.Refresh - onActivated: !!app.currentFolder ? Kube.Fabric.postMessage(Kube.Messages.synchronize, {"folder": app.currentFolder}) : Kube.Fabric.postMessage(Kube.Messages.synchronize, {"accountId": app.currentAccount}) + onActivated: { + if (!!app.currentFolder) { + Kube.Fabric.postMessage(Kube.Messages.synchronize, {"folder": app.currentFolder}); + Kube.Fabric.postMessage(Kube.Messages.synchronize, {"accountId": app.currentAccount, "type": "folder"}) + } else { + Kube.Fabric.postMessage(Kube.Messages.synchronize, {"accountId": app.currentAccount}) + } + } } //END Shortcuts diff --git a/framework/qml/FolderListView.qml b/framework/qml/FolderListView.qml index 25c6cbe5..a24a9ff6 100644 --- a/framework/qml/FolderListView.qml +++ b/framework/qml/FolderListView.qml @@ -30,6 +30,33 @@ Kube.TreeView { Controls1.TableViewColumn { title: "Name" role: "name" + delegate: Item { + DropArea { + anchors.fill: parent + Rectangle { + anchors.fill: parent + color: Kube.Colors.viewBackgroundColor + opacity: 0.3 + visible: parent.containsDrag + } + onDropped: { + Kube.Fabric.postMessage(Kube.Messages.moveToFolder, {"mail": drop.source.mail, "folder": model.domainObject}) + drop.accept(Qt.MoveAction) + drop.source.visible = false + } + } + + Kube.Label { + anchors { + verticalCenter: parent.verticalCenter + left: parent.left + right: parent.right + } + text: styleData.value + elide: Qt.ElideRight + color: model.hasNewData ? Kube.Colors.highlightColor : Kube.Colors.viewBackgroundColor + } + } } model: Kube.FolderListModel { @@ -43,11 +70,4 @@ Kube.TreeView { Kube.Fabric.postMessage(Kube.Messages.folderSelection, {"folder": model.data(index, Kube.FolderListModel.DomainObject), "trash": model.data(index, Kube.FolderListModel.Trash)}); } - - - onDropped: { - Kube.Fabric.postMessage(Kube.Messages.moveToFolder, {"mail": drop.source.mail, "folder": model.domainObject}) - drop.accept(Qt.MoveAction) - drop.source.visible = false - } } diff --git a/framework/qml/TreeView.qml b/framework/qml/TreeView.qml index eb140514..7b9a1103 100644 --- a/framework/qml/TreeView.qml +++ b/framework/qml/TreeView.qml @@ -36,12 +36,16 @@ FocusScope { * FIXME: This is what QItemSelectionModel selection vs current selection are for. Try to use that instead. */ property var activeIndex: null - signal dropped(var drop, var model) signal activated(var index) onActivated: { activeIndex = index } + function indexFromRow(row) { + //FIXME Uses internal API to get to the model index + return treeView.__model.mapRowToModelIndex(row) + } + Flickable { id: flickableItem @@ -115,8 +119,7 @@ FocusScope { style: TreeViewStyle { rowDelegate: Controls2.Control { id: delegateRoot - //FIXME Uses internal API to get to the model index - property bool isActive: root.activeIndex === treeView.__model.mapRowToModelIndex(styleData.row) + property bool isActive: root.activeIndex === indexFromRow(styleData.row) height: Kube.Units.gridUnit * 1.5 //FIXME This is the only way I could find to get the correct width. parent.width is way to wide width: parent.parent.parent ? parent.parent.parent.width : 0 @@ -145,30 +148,6 @@ FocusScope { text: styleData.isExpanded ? "-" : "+" } - itemDelegate: Item { - DropArea { - anchors.fill: parent - Rectangle { - anchors.fill: parent - color: Kube.Colors.viewBackgroundColor - opacity: 0.3 - visible: parent.containsDrag - } - onDropped: root.dropped(drop, model) - } - - Kube.Label { - anchors { - verticalCenter: parent.verticalCenter - left: parent.left - right: parent.right - } - text: styleData.value - elide: Qt.ElideRight - color: Kube.Colors.viewBackgroundColor - } - } - backgroundColor: Kube.Colors.textColor highlightedTextColor: Kube.Colors.highlightedTextColor } diff --git a/framework/src/domain/folderlistmodel.cpp b/framework/src/domain/folderlistmodel.cpp index f929b01e..6555abbf 100644 --- a/framework/src/domain/folderlistmodel.cpp +++ b/framework/src/domain/folderlistmodel.cpp @@ -21,6 +21,8 @@ #include "folderlistmodel.h" #include #include +#include +#include #include using namespace Sink; @@ -59,6 +61,7 @@ QHash< int, QByteArray > FolderListModel::roleNames() const roles[DomainObject] = "domainObject"; roles[Status] = "status"; roles[Trash] = "trash"; + roles[HasNewData] = "hasNewData"; return roles; } @@ -92,14 +95,46 @@ QVariant FolderListModel::data(const QModelIndex &idx, int role) const return folder->getSpecialPurpose().contains(Sink::ApplicationDomain::SpecialPurpose::Mail::trash); } return false; + case HasNewData: + return mHasNewData.contains(folder->identifier()); } return QSortFilterProxyModel::data(idx, role); } +static QModelIndex findRecursive(QAbstractItemModel *model, const QModelIndex &parent, int role, const QVariant &value) +{ + for (auto row = 0; row < model->rowCount(parent); row++) { + const auto idx = model->index(row, 0, parent); + if (model->data(idx, role) == value) { + return idx; + } + auto result = findRecursive(model, idx, role, value); + if (result.isValid()) { + return result; + } + } + return {}; +} + void FolderListModel::runQuery(const Query &query) { mModel = Store::loadModel(query); setSourceModel(mModel.data()); + + Sink::Query resourceQuery; + resourceQuery.setFilter(query.getResourceFilter()); + mNotifier.reset(new Sink::Notifier{resourceQuery}); + mNotifier->registerHandler([&](const Sink::Notification ¬ification) { + if (notification.type == Sink::Notification::Info && notification.code == ApplicationDomain::NewContentAvailable) { + if (!notification.entities.isEmpty()) { + mHasNewData.insert(notification.entities.first()); + auto idx = findRecursive(this, {}, Id, QVariant::fromValue(notification.entities.first())); + if (idx.isValid()) { + emit dataChanged(idx, idx); + } + } + } + }); } void FolderListModel::setAccountId(const QVariant &accountId) @@ -164,6 +199,12 @@ bool FolderListModel::acceptRow(int sourceRow, const QModelIndex &sourceParent) return enabled; } +void FolderListModel::fetchMore(const QModelIndex &parent) +{ + mHasNewData.remove(parent.data(Id).toByteArray()); + QAbstractItemModel::fetchMore(parent); +} + void FolderListModel::setFolderId(const QVariant &folderId) { const auto folder = folderId.toString().toUtf8(); diff --git a/framework/src/domain/folderlistmodel.h b/framework/src/domain/folderlistmodel.h index 738cf4a0..d3bef397 100644 --- a/framework/src/domain/folderlistmodel.h +++ b/framework/src/domain/folderlistmodel.h @@ -22,6 +22,8 @@ #include #include +#include +#include namespace Sink { class Query; @@ -54,7 +56,8 @@ public: Id, DomainObject, Status, - Trash + Trash, + HasNewData }; Q_ENUMS(Roles) @@ -68,8 +71,11 @@ public: protected: bool lessThan(const QModelIndex &left, const QModelIndex &right) const Q_DECL_OVERRIDE; bool acceptRow(int sourceRow, const QModelIndex &sourceParent) const Q_DECL_OVERRIDE; + void fetchMore(const QModelIndex &left) Q_DECL_OVERRIDE; private: void runQuery(const Sink::Query &query); QSharedPointer mModel; + QSet mHasNewData; + QScopedPointer mNotifier; }; diff --git a/framework/src/sinkfabric.cpp b/framework/src/sinkfabric.cpp index 8492f272..916cc8fa 100644 --- a/framework/src/sinkfabric.cpp +++ b/framework/src/sinkfabric.cpp @@ -203,6 +203,11 @@ public: if (notification.code == Sink::ApplicationDomain::TransmissionSuccess) { message["type"] = "info"; message["message"] = QObject::tr("A message has been sent."); + } else if (notification.code == Sink::ApplicationDomain::NewContentAvailable) { + message["type"] = "info"; + if (!notification.entities.isEmpty()) { + message["folderId"] = notification.entities.first(); + } } else { return; } -- cgit v1.2.3