diff --git a/framework/src/sinkfabric.cpp b/framework/src/sinkfabric.cpp index 42e6d817..0cd90b3f 100644 --- a/framework/src/sinkfabric.cpp +++ b/framework/src/sinkfabric.cpp @@ -1,256 +1,260 @@ /* Copyright (c) 2016 Christian Mollekopf This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "sinkfabric.h" #include #include #include #include #include #include #include "fabric.h" #include "keyring.h" using namespace Kube; using namespace Sink; using namespace Sink::ApplicationDomain; class SinkListener : public Kube::Fabric::Listener { public: SinkListener() = default; void notify(const QString &id, const QVariantMap &message) { SinkLog() << "Received message: " << id << message; if (id == "synchronize"/*Kube::Messages::synchronize*/) { if (auto folder = message["folder"].value()) { SinkLog() << "Synchronizing folder " << folder->resourceInstanceIdentifier() << folder->identifier(); auto scope = SyncScope().resourceFilter(folder->resourceInstanceIdentifier()).filter(QVariant::fromValue(folder->identifier())); scope.setType(); Store::synchronize(scope).exec(); } else if (message.contains("specialPurpose")) { auto specialPurpose = message["specialPurpose"].value(); //Synchronize all drafts folders if (specialPurpose == "drafts") { //TODO or rather just synchronize draft mails and have resource figure out what that means? Sink::Query folderQuery{}; folderQuery.containsFilter(Sink::ApplicationDomain::SpecialPurpose::Mail::drafts); folderQuery.request(); folderQuery.request(); Store::fetch(folderQuery) .then([] (const QList &folders) { for (const auto f : folders) { auto scope = SyncScope().resourceFilter(f->resourceInstanceIdentifier()).filter(QVariant::fromValue(f->identifier())); scope.setType(); Store::synchronize(scope).exec(); } }).exec(); } } else { auto accountId = message["accountId"].value(); auto type = message["type"].value(); SyncScope scope; if (!accountId.isEmpty()) { //FIXME this should work with either string or bytearray, but is apparently very picky scope.resourceFilter(accountId.toLatin1()); } if (type == "contacts") { scope.setType(); + } else if (type == "event") { + scope.setType(); + } else if (type == "calendar") { + scope.setType(); } else if (type == "mail") { scope.setType(); } else if (type == "folder") { scope.setType(); } else { //Only synchronize folders by default for now scope.setType(); } SinkLog() << "Synchronizing... AccountId: " << accountId << " Type: " << scope.type(); Store::synchronize(scope).exec(); } } if (id == "sendOutbox"/*Kube::Messages::synchronize*/) { Query query; query.containsFilter(ResourceCapabilities::Mail::transport); auto job = Store::fetchAll(query) .each([=](const SinkResource::Ptr &resource) -> KAsync::Job { return Store::synchronize(SyncScope{}.resourceFilter(resource->identifier())); }); job.exec(); } if (id == "markAsRead"/*Kube::Messages::synchronize*/) { if (auto mail = message["mail"].value()) { mail->setUnread(false); Store::modify(*mail).exec(); } } if (id == "markAsUnread"/*Kube::Messages::synchronize*/) { if (auto mail = message["mail"].value()) { mail->setUnread(true); Store::modify(*mail).exec(); } } if (id == "setImportant"/*Kube::Messages::synchronize*/) { if (auto mail = message["mail"].value()) { mail->setImportant(message["important"].toBool()); Store::modify(*mail).exec(); } } if (id == "moveToTrash"/*Kube::Messages::synchronize*/) { if (auto mail = message["mail"].value()) { mail->setTrash(true); Store::modify(*mail).exec(); } } if (id == "moveToDrafts"/*Kube::Messages::synchronize*/) { if (auto mail = message["mail"].value()) { mail->setDraft(true); Store::modify(*mail).exec(); } } if (id == "moveToFolder"/*Kube::Messages::synchronize*/) { if (auto mail = message["mail"].value()) { auto folder = message["folder"].value(); mail->setFolder(*folder); Store::modify(*mail).exec(); } } if (id == "unlockKeyring") { auto accountId = message["accountId"].value(); Kube::AccountKeyring{accountId}.unlock(); } } }; class SinkNotifier { public: SinkNotifier() : mNotifier{Sink::Query{Sink::Query::LiveQuery}} { mNotifier.registerHandler([] (const Sink::Notification ¬ification) { Notification n; SinkLog() << "Received notification: " << notification; QVariantMap message; if (notification.type == Sink::Notification::Warning) { message["type"] = "warning"; QVariantList entities; for(const auto &entity : notification.entities) { entities << entity; } message["entities"] = entities; message["resource"] = QString{notification.resource}; if (notification.code == Sink::ApplicationDomain::TransmissionError) { message["message"] = QObject::tr("Failed to send message."); message["subtype"] = "transmissionError"; } else { return; } } else if (notification.type == Sink::Notification::Status) { return; } else if (notification.type == Sink::Notification::Error) { message["type"] = "error"; message["resource"] = QString{notification.resource}; message["details"] = notification.message; switch(notification.code) { case Sink::ApplicationDomain::ConnectionError: message["message"] = QObject::tr("Failed to connect to server."); message["subtype"] = "connectionError"; break; case Sink::ApplicationDomain::NoServerError: message["message"] = QObject::tr("Host not found."); message["subtype"] = "hostNotFoundError"; break; case Sink::ApplicationDomain::LoginError: message["message"] = QObject::tr("Failed to login."); message["subtype"] = "loginError"; break; case Sink::ApplicationDomain::ConfigurationError: message["message"] = QObject::tr("Configuration error."); break; case Sink::ApplicationDomain::ConnectionLostError: message["message"] = QObject::tr("Connection lost."); break; case Sink::ApplicationDomain::MissingCredentialsError: message["message"] = QObject::tr("No credentials available."); break; default: //Ignore unknown errors, they are not going to help. return; } Fabric::Fabric{}.postMessage("errorNotification", message); } else if (notification.type == Sink::Notification::Info) { 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; } } else if (notification.type == Sink::Notification::Progress) { message["type"] = "progress"; message["progress"] = notification.progress; message["total"] = notification.total; if (!notification.entities.isEmpty()) { message["folderId"] = notification.entities.first(); } message["resourceId"] = notification.resource; Fabric::Fabric{}.postMessage("progressNotification", message); return; } else { return; } Fabric::Fabric{}.postMessage("notification", message); }); } Sink::Notifier mNotifier; }; class SinkFabric::Private { SinkNotifier notifier; SinkListener listener; }; SinkFabric::SinkFabric() : QObject(), d(new SinkFabric::Private) { } SinkFabric::~SinkFabric() { delete d; } SinkFabric &SinkFabric::instance() { static SinkFabric instance; return instance; } diff --git a/views/calendar/qml/View.qml b/views/calendar/qml/View.qml index c46b9480..5efda663 100644 --- a/views/calendar/qml/View.qml +++ b/views/calendar/qml/View.qml @@ -1,110 +1,114 @@ /* * Copyright (C) 2018 Michael Bohlender, * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import QtQuick 2.9 -import QtQuick.Controls 1.3 as Controls1 +import QtQuick.Controls 2.1 import QtQuick.Layouts 1.2 import org.kube.framework 1.0 as Kube RowLayout { id: root //TODO update every second property date currentDate: new Date() anchors.fill: parent + StackView.onActivated: { + Kube.Fabric.postMessage(Kube.Messages.synchronize, {"type": "event"}) + } + Rectangle { width: Kube.Units.gridUnit * 10 Layout.fillHeight: parent.height color: Kube.Colors.darkBackgroundColor Kube.PositiveButton { id: newEventButton objectName: "newEventButton" anchors { top: parent.top left: parent.left right: parent.right margins: Kube.Units.largeSpacing } focus: true text: qsTr("New Event") onClicked: {} } Column { anchors { top: newEventButton.bottom left: newEventButton.left topMargin: Kube.Units.largeSpacing } width: parent.width spacing: Kube.Units.smallSpacing Kube.Label { text: "Week" color: Kube.Colors.highlightedTextColor } Kube.Label { text: "Month" color: Kube.Colors.highlightedTextColor } Kube.Label { text: "Agenda" color: Kube.Colors.highlightedTextColor } } Column { anchors { bottom: parent.bottom left: newEventButton.left bottomMargin: Kube.Units.largeSpacing } spacing: Kube.Units.smallSpacing Repeater { model: ["calendar_1","calendar_2","calendar_3"] delegate: Row { spacing: Kube.Units.smallSpacing Kube.CheckBox { opacity: 0.9 } Kube.Label { text: modelData color: Kube.Colors.highlightedTextColor } } } } } WeekView { Layout.fillHeight: true Layout.fillWidth: true currentDate: root.currentDate } }