Warning, /pim/kube/views/inbound/qml/View.qml is written in an unsupported language. File is not indexed.

0001 /*
0002  *  Copyright (C) 2021 Christian Mollekopf, <mollekopf@kolabsys.com>
0003  *
0004  *  This program is free software; you can redistribute it and/or modify
0005  *  it under the terms of the GNU General Public License as published by
0006  *  the Free Software Foundation; either version 2 of the License, or
0007  *  (at your option) any later version.
0008  *
0009  *  This program is distributed in the hope that it will be useful,
0010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0012  *  GNU General Public License for more details.
0013  *
0014  *  You should have received a copy of the GNU General Public License along
0015  *  with this program; if not, write to the Free Software Foundation, Inc.,
0016  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
0017  */
0018 
0019 import QtQuick 2.15
0020 import QtQuick.Layouts 1.15
0021 import QtQuick.Controls 1.3 as Controls1
0022 import QtQuick.Controls 2
0023 import org.kube.framework 1.0 as Kube
0024 
0025 import "dateutils.js" as DateUtils
0026 
0027 Kube.View {
0028     id: root
0029 
0030     property bool pendingError: false
0031     property bool pendingNotification: false
0032 
0033     property var modelFilter: {
0034         "inbound": true,
0035         "recent": false,
0036         "important": false,
0037         "folder": null,
0038         "string": root.filter,
0039         "headersOnly": true,
0040     }
0041 
0042     property var currentFolder: null
0043 
0044     onPendingErrorChanged: {
0045         Kube.Fabric.postMessage(Kube.Messages.errorPending, {errorPending: pendingError})
0046     }
0047 
0048     onPendingNotificationChanged: {
0049         Kube.Fabric.postMessage(Kube.Messages.notificationPending, {notificationPending: pendingNotification})
0050     }
0051 
0052     //We have to hardcode because all the mapToItem/mapFromItem functions are garbage
0053     searchArea: Qt.rect(ApplicationWindow.window.sidebarWidth + listItem.x, 0, (details.x + details.width) - listItem.x, (details.y + details.height) - listItem.y)
0054 
0055     onFilterChanged: {
0056         if (filter) {
0057             inboundModel.enableNotifications = false;
0058         } else {
0059             inboundModel.enableNotifications = true;
0060         }
0061         root.modelFilter = {
0062             "inbound": root.modelFilter.inbound,
0063             "recent": root.modelFilter.recent,
0064             "important": root.modelFilter.important,
0065             "folder": root.modelFilter.folder,
0066             "string": filter,
0067             "headersOnly": true
0068         }
0069         Kube.Fabric.postMessage(Kube.Messages.searchString, {"searchString": filter})
0070     }
0071 
0072     Kube.Listener {
0073         filter: Kube.Messages.folderSelection
0074         onMessageReceived: {
0075             root.currentFolder = message.folder
0076             accountSwitcher.selectEntity(message.folder)
0077         }
0078     }
0079 
0080     onActivated: {
0081         //In case of an initial load we may have positioned before the view is actually expanded,
0082         //so position again once the view is activated.
0083         listView.positionViewAtIndex(listView.currentIndex, ListView.Center);
0084     }
0085 
0086     onRefresh: {
0087         if (!root.modelFilter.inbound && !!root.currentFolder) {
0088             Kube.Fabric.postMessage(Kube.Messages.synchronize, {"folder": root.currentFolder});
0089             Kube.Fabric.postMessage(Kube.Messages.synchronize, {"accountId": Kube.Context.currentAccountId, "type": "folder"})
0090         } else {
0091             Kube.Fabric.postMessage(Kube.Messages.synchronize, {})
0092         }
0093     }
0094 
0095     onCurrentFolderChanged: {
0096         if (!!root.currentFolder) {
0097             root.modelFilter = {
0098                 "inbound": false,
0099                 "recent": false,
0100                 "important": false,
0101                 "folder": accountSwitcher.currentEntity,
0102                 "string": root.filter,
0103             }
0104         }
0105     }
0106 
0107     Kube.Listener {
0108         filter: Kube.Messages.search
0109         onMessageReceived: root.triggerSearch()
0110     }
0111 
0112     helpViewComponent: Kube.HelpPopup {
0113         ListModel {
0114             ListElement { description: qsTr("Jump to top of threadlist:"); shortcut: "t" }
0115             ListElement { description: qsTr("Jump to next thread:"); shortcut: "j" }
0116             ListElement { description: qsTr("Jump to previous thread:"); shortcut: "k" }
0117             ListElement { description: qsTr("Jump to next message:"); shortcut: "n" }
0118             ListElement { description: qsTr("Jump to previous message:"); shortcut: "p" }
0119             ListElement { description: qsTr("Jump to next folder:"); shortcut: "f,n" }
0120             ListElement { description: qsTr("Jump to previous folder:"); shortcut: "f,p" }
0121             ListElement { description: qsTr("Compose new message:"); shortcut: "c" }
0122             ListElement { description: qsTr("Reply to the currently focused message:"); shortcut: "r" }
0123             ListElement { description: qsTr("Delete the currently focused message:"); shortcut: "d" }
0124             ListElement { description: qsTr("Mark the currently focused message as important:"); shortcut: "i" }
0125             ListElement { description: qsTr("Mark the currently focused message as unread:"); shortcut: "u" }
0126             ListElement { description: qsTr("Show this help text:"); shortcut: "?" }
0127         }
0128     }
0129 
0130     Shortcut {
0131         enabled: root.isCurrentView
0132         sequences: ['j']
0133         onActivated: Kube.Fabric.postMessage(Kube.Messages.selectNextConversation, {})
0134     }
0135     Shortcut {
0136         enabled: root.isCurrentView
0137         sequences: ['k']
0138         onActivated: Kube.Fabric.postMessage(Kube.Messages.selectPreviousConversation, {})
0139     }
0140     Shortcut {
0141         enabled: root.isCurrentView
0142         sequences: ['t']
0143         onActivated: Kube.Fabric.postMessage(Kube.Messages.selectTopConversation, {})
0144     }
0145     Shortcut {
0146         enabled: root.isCurrentView
0147         sequences: ['Shift+J']
0148         onActivated: Kube.Fabric.postMessage(Kube.Messages.scrollConversationDown, {})
0149     }
0150     Shortcut {
0151         enabled: root.isCurrentView
0152         sequences: ['Shift+K']
0153         onActivated: Kube.Fabric.postMessage(Kube.Messages.scrollConversationUp, {})
0154     }
0155     Shortcut {
0156         sequences: ['n']
0157         onActivated: Kube.Fabric.postMessage(Kube.Messages.selectNextMessage, {})
0158     }
0159     Shortcut {
0160         enabled: root.isCurrentView
0161         sequences: ['p']
0162         onActivated: Kube.Fabric.postMessage(Kube.Messages.selectPreviousMessage, {})
0163     }
0164     Shortcut {
0165         enabled: root.isCurrentView
0166         sequences: ['f,n']
0167         onActivated: Kube.Fabric.postMessage(Kube.Messages.selectNextFolder, {})
0168     }
0169     Shortcut {
0170         enabled: root.isCurrentView
0171         sequences: ['f,p']
0172         onActivated: Kube.Fabric.postMessage(Kube.Messages.selectPreviousFolder, {})
0173     }
0174     Shortcut {
0175         enabled: root.isCurrentView
0176         sequences: ['c']
0177         onActivated: Kube.Fabric.postMessage(Kube.Messages.compose, {})
0178     }
0179     Shortcut {
0180         enabled: root.isCurrentView
0181         sequence: "?"
0182         onActivated: root.showHelp()
0183     }
0184 
0185     Controls1.SplitView {
0186         Layout.fillWidth: true
0187         Layout.fillHeight: true
0188 
0189         Kube.LeftSidebar {
0190             Layout.fillHeight: parent.height
0191             buttons: [
0192                 Kube.PositiveButton {
0193                     id: newMailButton
0194                     objectName: "newMailButton"
0195                     Layout.fillWidth: true
0196                     focus: true
0197                     text: qsTr("New Email")
0198                     onClicked: Kube.Fabric.postMessage(Kube.Messages.compose, {})
0199                 },
0200                 ColumnLayout {
0201                     Kube.TextButton {
0202                         Layout.fillWidth: true
0203                         text: qsTr("Inbound")
0204                         textColor: Kube.Colors.highlightedTextColor
0205                         checkable: true
0206                         checked: root.modelFilter.inbound
0207                         horizontalAlignment: Text.AlignHLeft
0208                         onClicked: {
0209                             root.modelFilter = {
0210                                 "inbound": true,
0211                                 "recent": false,
0212                                 "important": false,
0213                                 "folder": null,
0214                                 "string": root.filter,
0215                                 "headersOnly": true,
0216                             }
0217                             accountSwitcher.clearSelection()
0218                         }
0219                         Kube.IconButton {
0220                             anchors {
0221                                 right: parent.right
0222                                 verticalCenter: parent.verticalCenter
0223                             }
0224                             visible: parent.hovered
0225                             padding: 0
0226                             iconName: Kube.Icons.overflowMenu_inverted
0227                             onClicked: {
0228                                 configComponent.createObject(root).open()
0229                             }
0230                             activeFocusOnTab: false
0231                             tooltip: qsTr("Configure")
0232                         }
0233                     }
0234                     Kube.TextButton {
0235                         Layout.fillWidth: true
0236                         text: qsTr("Recent")
0237                         textColor: Kube.Colors.highlightedTextColor
0238                         checkable: true
0239                         checked: root.modelFilter.recent
0240                         horizontalAlignment: Text.AlignHLeft
0241                         onClicked: {
0242                             root.modelFilter = {
0243                                 "inbound": false,
0244                                 "recent": true,
0245                                 "important": false,
0246                                 "folder": null,
0247                                 "string": root.filter,
0248                                 "headersOnly": true,
0249                             }
0250                             accountSwitcher.clearSelection()
0251                         }
0252                     }
0253                     Kube.TextButton {
0254                         Layout.fillWidth: true
0255                         text: qsTr("Important")
0256                         textColor: Kube.Colors.highlightedTextColor
0257                         checkable: true
0258                         checked: root.modelFilter.important
0259                         horizontalAlignment: Text.AlignHLeft
0260                         onClicked: {
0261                             root.modelFilter = {
0262                                 "inbound": false,
0263                                 "recent": false,
0264                                 "important": true,
0265                                 "folder": null,
0266                                 "string": root.filter,
0267                                 "headersOnly": true,
0268                             }
0269                             accountSwitcher.clearSelection()
0270                         }
0271                     }
0272                 }
0273             ]
0274 
0275 
0276             Kube.EntitySelector {
0277                 id: accountSwitcher
0278                 Layout.fillWidth: true
0279                 Layout.fillHeight: true
0280                 activeFocusOnTab: true
0281                 selectionEnabled: true
0282                 entityType: "folder"
0283                 roles: ["name", "enabled"]
0284                 sortRole: "customMail"
0285                 Kube.EntityController {
0286                     id: entityController
0287                 }
0288                 onEntityCreated: {
0289                     entityController.create({type: entityType, account: accountId, entity: {
0290                         "name": text,
0291                         "enabled": true,
0292                     }})
0293                 }
0294                 onEntityRemoved: {
0295                     entityController.remove(entityType, entity)
0296                 }
0297                 onCurrentEntityChanged: {
0298                     Kube.Fabric.postMessage(Kube.Messages.folderSelection, {
0299                         "folder": currentEntity,
0300                         "trash": false
0301                     })
0302                 }
0303             }
0304         }
0305 
0306         StackLayout {
0307             width: parent.width/3
0308             Layout.fillHeight: true
0309 
0310             Item {
0311                 id: listItem
0312 
0313                 function reselect() {
0314                     console.warn("Reselect")
0315                     var idx = listView.currentIndex
0316                     listView.currentIndex = -1;
0317                     listView.currentIndex = idx;
0318                 }
0319 
0320                 Kube.Listener {
0321                     filter: Kube.Messages.selectTopConversation
0322                     onMessageReceived: {
0323                         listView.currentIndex = 0
0324                         listView.forceActiveFocus()
0325                     }
0326                 }
0327 
0328                 Kube.Listener {
0329                     filter: Kube.Messages.selectNextConversation
0330                     onMessageReceived: {
0331                         listView.incrementCurrentIndex()
0332                         listView.forceActiveFocus()
0333                     }
0334                 }
0335 
0336                 Kube.Listener {
0337                     filter: Kube.Messages.selectPreviousConversation
0338                     onMessageReceived: {
0339                         listView.decrementCurrentIndex()
0340                         listView.forceActiveFocus()
0341                     }
0342                 }
0343 
0344                 Kube.Label {
0345                     anchors.centerIn: parent
0346                     visible: listView.count == 0
0347                     text: qsTr("Nothing here...")
0348                 }
0349 
0350                 Component {
0351                     id: sectionHeading
0352                     Rectangle {
0353                         width: ListView.view.width
0354                         height: childrenRect.height
0355 
0356                         Kube.Heading {
0357                             text: section == "event" ? "Coming up" : "Recently"
0358                         }
0359                     }
0360                 }
0361 
0362                 Kube.ListView {
0363                     id: listView
0364                     objectName: "listView"
0365                     anchors.fill: parent
0366 
0367                     clip: true
0368                     focus: true
0369                     reuseItems: true
0370 
0371                     property double startTime: 0
0372 
0373                     onActiveFocusChanged: {
0374                         if (activeFocus && currentIndex < 0) {
0375                             currentIndex = 0
0376                         }
0377                     }
0378 
0379                     section {
0380                         property: "type"
0381                         criteria: ViewSection.FullString
0382                         delegate: root.modelFilter.inbound ? sectionHeading : null
0383                     }
0384 
0385                     Keys.onPressed: {
0386                         //Not implemented as a shortcut because we want it only to apply if we have the focus
0387                         if (currentItem.currentData.data.mail) {
0388                             var currentMail = currentItem.currentData.data.mail;
0389                             if (event.text == "d" || event.key == Qt.Key_Delete) {
0390                                 Kube.Fabric.postMessage(Kube.Messages.moveToTrash, {"mail": currentMail})
0391                             } else if (event.text == "r") {
0392                                 Kube.Fabric.postMessage(Kube.Messages.reply, {"mail": currentMail})
0393                             } else if (event.text == "i") {
0394                                 Kube.Fabric.postMessage(Kube.Messages.setImportant, {"mail": currentMail, "important": !currentItem.currentData.data.important})
0395                             } else if (event.text == "u") {
0396                                 Kube.Fabric.postMessage(Kube.Messages.markAsUnread, {"mail": currentMail})
0397                             }
0398                         }
0399                         if (event.key == Qt.Key_Home) {
0400                             listView.currentIndex = 0
0401                         }
0402                     }
0403 
0404                     model: Kube.InboundModel {
0405                         id: inboundModel
0406                         objectName: "inboundModel"
0407                         property var enableNotifications: false
0408                         onEntryAdded: {
0409                             if (enableNotifications) {
0410                                 Kube.Fabric.postMessage(Kube.Messages.displayNotification, message)
0411                             }
0412                         }
0413 
0414                         filter: root.modelFilter
0415 
0416                         onFilterChanged: {
0417                             enableNotifications = false;
0418                             //Avoid selecting each item at the current index until the initial items are loaded
0419                             listView.currentIndex = -1;
0420                             listView.startTime = new Date().getTime()
0421                         }
0422 
0423                         onFetchingMore: {
0424                             enableNotifications = false;
0425                         }
0426 
0427                         onInitialItemsLoaded: {
0428                             enableNotifications = true;
0429                             //Because this is also emitted on fetchMore
0430                             if (listView.currentIndex == -1) {
0431                                 //Make sure the view is up-to-date before positioning
0432                                 listView.forceLayout()
0433                                 listView.currentIndex = inboundModel.firstRecentIndex();
0434                                 listView.positionViewAtIndex(listView.currentIndex, ListView.Center);
0435                                 console.info("Initial items loaded: " + (new Date().getTime() - listView.startTime) + " ms")
0436                             }
0437                         }
0438                         currentDate: Kube.Context.currentDate
0439                     }
0440 
0441                     onCurrentItemChanged: {
0442                         if (!currentItem || !currentItem.currentData) {
0443                             details.subtype = ""
0444                             return
0445                         }
0446                         var currentData = currentItem.currentData;
0447                         if (!!currentData.resource) {
0448                             details.resourceId = currentData.resource
0449                         }
0450                         details.message = currentData.message + "\n" + currentItem.currentData.details
0451                         details.timestamp = currentData.timestamp
0452                         details.entities = currentData.entities
0453                         details.itemData = currentData.data
0454                         if (!!currentData.subtype) {
0455                             details.subtype = currentData.subtype
0456                         } else {
0457                             details.subtype = ""
0458                         }
0459                         if (currentData.data.mail && currentData.data.unread) {
0460                             Kube.Fabric.postMessage(Kube.Messages.markAsRead, {"mail": currentData.data.mail})
0461                         }
0462                     }
0463 
0464                     delegate: Kube.GenericListDelegate {
0465                         id: delegateRoot
0466 
0467                         property bool isMail: model.type == "mail"
0468                         property var domainObject: model.data.domainObject
0469                         property bool important: isMail && model.data.important
0470                         height: Kube.Units.gridUnit * 3 + 2 * Kube.Units.smallSpacing
0471 
0472                         onDropped: {
0473                             if (dropAction == Qt.MoveAction) {
0474                                 if (isMail) {
0475                                     delegateRoot.visible = false
0476                                     Kube.Fabric.postMessage(Kube.Messages.moveToFolder, {"mail": delegateRoot.domainObject, "folderId": dropTarget.targetId})
0477                                 } else {
0478                                     Kube.Fabric.postMessage(Kube.Messages.moveToCalendar, {"event": delegateRoot.domainObject, "calendarId": dropTarget.targetId})
0479                                 }
0480                             }
0481                         }
0482 
0483                         function formatStartDateTime(date, today) {
0484                             if (DateUtils.sameDay(date, today)) {
0485                                 return qsTr("Today, ")+ Qt.formatDateTime(date, "hh:mm")
0486                             }
0487 
0488                             const daysTo = DateUtils.daysSince(date, today)
0489                             if (daysTo == 1) {
0490                                 return qsTr("Tomorrow, ") + Qt.formatDateTime(date, "hh:mm")
0491                             }
0492                             if (daysTo <= 7) {
0493                                 return Qt.formatDateTime(date, "dddd") + qsTr(" (in %1 days)").arg(daysTo)
0494                             }
0495                             if (date.getTime() < today.getTime()) {
0496                                 return qsTr("%1 days ago").arg(DateUtils.daysSince(today, date))
0497                             }
0498                             return Qt.formatDateTime(date, "dd MMM yyyy")
0499                         }
0500 
0501                         function formatDateTime(date) {
0502                             const today = new Date()
0503                             if (DateUtils.sameDay(date, today)) {
0504                                 return Qt.formatDateTime(date, "hh:mm")
0505                             }
0506                             const lastWeekToday = today.getTime() - ((24*60*60*1000) * 7);
0507                             if (date.getTime() >= lastWeekToday) {
0508                                 return Qt.formatDateTime(date, "ddd hh:mm")
0509                             }
0510                             return Qt.formatDateTime(date, "dd MMM yyyy")
0511                         }
0512 
0513                         mainText: model.data.subject
0514                         subText: isMail ? model.data.senderName : model.data.calendar
0515                         dateText: isMail ? formatDateTime(model.data.date) : formatStartDateTime(model.data.date, Kube.Context.currentDate)
0516                         active: model.data.unread
0517                         disabled: model.data.complete
0518                         strikeout: model.data.complete ? model.data.complete : false
0519                         counter: isMail ? model.data.threadSize : 0
0520                         subtextVisible: true
0521                         subtextDisabled: false
0522 
0523                         Component {
0524                             id: importantStatusComponent
0525                             Kube.Icon {
0526                                 iconName: Kube.Icons.isImportant
0527                                 visible:  delegateRoot.important
0528                             }
0529                         }
0530 
0531                         statusDelegate: isMail ? importantStatusComponent : null
0532 
0533                         Component {
0534                             id: mailButtonComponent
0535                             Row {
0536                                 Column {
0537                                     Kube.IconButton {
0538                                         id: ignoreButton
0539                                         visible: root.modelFilter.inbound
0540                                         padding: 0
0541                                         iconName: Kube.Icons.listRemove
0542                                         onClicked: inboundModel.ignoreSender(delegateRoot.domainObject)
0543                                         activeFocusOnTab: false
0544                                         tooltip: qsTr("Ignore sender")
0545                                     }
0546                                 }
0547                                 Column {
0548                                     Kube.IconButton {
0549                                         id: restoreButton
0550                                         iconName: Kube.Icons.undo
0551                                         visible: !!delegateRoot.trash
0552                                         padding: 0
0553                                         onClicked: Kube.Fabric.postMessage(Kube.Messages.restoreFromTrash, {"mail": delegateRoot.domainObject})
0554                                         activeFocusOnTab: false
0555                                         tooltip: qsTr("Restore from trash")
0556                                     }
0557 
0558                                     Kube.IconButton {
0559                                         id: readButton
0560                                         iconName: Kube.Icons.markAsRead
0561                                         visible: model.data.unread && !model.data.trash
0562                                         padding: 0
0563                                         onClicked: {
0564                                             Kube.Fabric.postMessage(Kube.Messages.markAsRead, {"mail": delegateRoot.domainObject})
0565                                         }
0566                                         tooltip: qsTr("Mark as read")
0567                                     }
0568 
0569                                     Kube.IconButton {
0570                                         id: unreadButton
0571                                         iconName: Kube.Icons.markAsUnread
0572                                         visible: !model.data.unread && !model.data.trash
0573                                         padding: 0
0574                                         onClicked: Kube.Fabric.postMessage(Kube.Messages.markAsUnread, {"mail": delegateRoot.domainObject})
0575                                         activeFocusOnTab: false
0576                                         tooltip: qsTr("Mark as unread")
0577                                     }
0578 
0579                                     Kube.IconButton {
0580                                         id: importantButton
0581                                         iconName: delegateRoot.important ? Kube.Icons.markImportant : Kube.Icons.markUnimportant
0582                                         visible: !!delegateRoot.domainObject
0583                                         padding: 0
0584                                         onClicked: Kube.Fabric.postMessage(Kube.Messages.setImportant, {"mail": delegateRoot.domainObject, "important": !model.data.important})
0585                                         activeFocusOnTab: false
0586                                         tooltip: qsTr("Mark as important")
0587                                     }
0588 
0589                                     Kube.IconButton {
0590                                         id: deleteButton
0591                                         objectName: "deleteButton"
0592                                         iconName: Kube.Icons.moveToTrash
0593                                         visible: !!delegateRoot.domainObject
0594                                         padding: 0
0595                                         onClicked: Kube.Fabric.postMessage(Kube.Messages.moveToTrash, {"mail": delegateRoot.domainObject})
0596                                         activeFocusOnTab: false
0597                                         tooltip: qsTr("Move to trash")
0598                                     }
0599                                 }
0600                             }
0601                         }
0602 
0603                         Component {
0604                             id: eventButtonComponent
0605                             Column {
0606                                 //Cancel
0607                                 //Reschedule
0608                                 //Ignore?
0609                                 Kube.IconButton {
0610                                     iconName: Kube.Icons.checkbox
0611                                     activeFocusOnTab: false
0612                                     tooltip: qsTr("Done!")
0613                                     padding: 0
0614                                 }
0615                             }
0616                         }
0617 
0618                         buttonDelegate: isMail ? mailButtonComponent : eventButtonComponent
0619 
0620                     }
0621                 }
0622             }
0623         }
0624 
0625         Item {
0626             id: details
0627             property string subtype: ""
0628             property date timestamp
0629             property string message: ""
0630             property string resourceId: ""
0631             property var entities: []
0632             property var itemData: null
0633 
0634             Kube.ModelIndexRetriever {
0635                 id: retriever
0636                 model: Kube.AccountsModel {
0637                     resourceId: details.resourceId
0638                 }
0639             }
0640 
0641             Loader {
0642                 id: detailsLoader
0643                 visible: message != ""
0644                 clip: true
0645                 anchors {
0646                     fill: parent
0647                 }
0648                 property date timestamp: details.timestamp
0649                 property string message: details.message
0650                 property string resourceId: details.resourceId
0651                 property string accountId: retriever.currentData ? retriever.currentData.accountId : ""
0652                 property string accountName: retriever.currentData ? retriever.currentData.name : ""
0653                 property string entityId: (details.entities && details.entities.length != 0) ? details.entities[0] : ""
0654                 property var itemData: details.itemData
0655 
0656                 function getComponent(subtype) {
0657                     if (subtype == Kube.Notifications.loginError) {
0658                         return loginErrorComponent
0659                     }
0660                     if (subtype == Kube.Notifications.hostNotFoundError) {
0661                         return hostNotFoundErrorComponent
0662                     }
0663                     if (subtype == Kube.Notifications.connectionError) {
0664                         return hostNotFoundErrorComponent
0665                     }
0666                     if (subtype == Kube.Notifications.transmissionError) {
0667                         return transmissionErrorComponent
0668                     }
0669                     if (subtype == Kube.Notifications.messageSent) {
0670                         return transmissionSuccessComponent
0671                     }
0672                     if (subtype == "mail") {
0673                         return conversationComponent
0674                     }
0675 
0676                     if (subtype == "event") {
0677                         return eventComponent
0678                     }
0679                     return detailsComponent
0680                 }
0681 
0682                 sourceComponent: getComponent(details.subtype)
0683             }
0684         }
0685     }
0686 
0687     Component {
0688         id: detailsComponent
0689         Rectangle {
0690             color: Kube.Colors.viewBackgroundColor
0691             GridLayout {
0692                 id: gridLayout
0693                 Layout.minimumWidth: 0
0694                 anchors {
0695                     top: parent.top
0696                     left: parent.left
0697                     right: parent.right
0698                 }
0699                 columns: 2
0700                 Kube.Label {
0701                     text: qsTr("Account:")
0702                     visible: accountName
0703                 }
0704                 Kube.Label {
0705                     Layout.fillWidth: true
0706                     text: accountName
0707                     visible: accountName
0708                     elide: Text.ElideRight
0709                 }
0710                 Kube.Label {
0711                     text: qsTr("Account Id:")
0712                     visible: accountId
0713                 }
0714                 Kube.Label {
0715                     text: accountId
0716                     visible: accountId
0717                     Layout.fillWidth: true
0718                     elide: Text.ElideRight
0719                 }
0720                 Kube.Label {
0721                     text: qsTr("Resource Id:")
0722                     visible: resourceId
0723                 }
0724                 Kube.Label {
0725                     text: resourceId
0726                     visible: resourceId
0727                     Layout.fillWidth: true
0728                     elide: Text.ElideRight
0729                 }
0730                 Kube.Label {
0731                     text: qsTr("Timestamp:")
0732                 }
0733                 Kube.Label {
0734                     text: Qt.formatDateTime(timestamp, " hh:mm:ss dd MMM yyyy")
0735                     Layout.fillWidth: true
0736                     elide: Text.ElideRight
0737                 }
0738                 Kube.Label {
0739                     text: qsTr("Message:")
0740                     Layout.alignment: Qt.AlignTop
0741                 }
0742                 Kube.Label {
0743                     text: message
0744                     Layout.fillWidth: true
0745                     wrapMode: Text.Wrap
0746                 }
0747                 Item {
0748                     Layout.columnSpan: 2
0749                     Layout.fillHeight: true
0750                     Layout.fillWidth: true
0751                 }
0752             }
0753 
0754             Kube.SelectableItem {
0755                 layout: gridLayout
0756             }
0757         }
0758     }
0759 
0760     Component {
0761         id: loginErrorComponent
0762         Item {
0763             Column {
0764                 anchors {
0765                     top: parent.top
0766                     left: parent.left
0767                     right: parent.right
0768                 }
0769                 spacing: Kube.Units.largeSpacing
0770                 Column {
0771                     Kube.Heading {
0772                         id: heading
0773                         text: qsTr("Failed to login")
0774                         color: Kube.Colors.warningColor
0775                     }
0776 
0777                     Kube.Label {
0778                         id: subHeadline
0779                         text: qsTr("%1: please check your credentials.").arg(accountName)
0780                         color: Kube.Colors.disabledTextColor
0781                         wrapMode: Text.Wrap
0782                     }
0783                 }
0784                 Kube.Button {
0785                     text: qsTr("Change Password")
0786                     onClicked: {
0787                         Kube.Fabric.postMessage(Kube.Messages.componentDone, {})
0788                         Kube.Fabric.postMessage(Kube.Messages.requestLogin, {accountId: accountId})
0789                     }
0790                 }
0791             }
0792         }
0793     }
0794 
0795     Component {
0796         id: hostNotFoundErrorComponent
0797         Item {
0798             Column {
0799                 anchors {
0800                     top: parent.top
0801                     left: parent.left
0802                     right: parent.right
0803                 }
0804                 spacing: Kube.Units.largeSpacing
0805                 Column {
0806                     Kube.Heading {
0807                         id: heading
0808                         text: qsTr("Host not found")
0809                         color: Kube.Colors.warningColor
0810                     }
0811 
0812                     Kube.Label {
0813                         id: subHeadline
0814                         text: qsTr("%1: please check your network connection and settings.").arg(accountName)
0815                         color: Kube.Colors.disabledTextColor
0816                         wrapMode: Text.Wrap
0817                     }
0818                 }
0819                 Kube.Button {
0820                     text: qsTr("Account Settings")
0821                     onClicked: {
0822                         Kube.Fabric.postMessage(Kube.Messages.componentDone, {})
0823                         Kube.Fabric.postMessage(Kube.Messages.requestAccountsConfiguration, {})
0824                     }
0825                 }
0826             }
0827         }
0828     }
0829 
0830     Component {
0831         id: transmissionErrorComponent
0832         Item {
0833             id: componentRoot
0834             Column {
0835                 anchors {
0836                     top: parent.top
0837                     left: parent.left
0838                     right: parent.right
0839                 }
0840                 spacing: Kube.Units.largeSpacing
0841 
0842                 Kube.Heading {
0843                     id: heading
0844                     text: qsTr("Failed to send the message.")
0845                     color: Kube.Colors.warningColor
0846                 }
0847 
0848                 Column {
0849                     spacing: Kube.Units.largeSpacing
0850 
0851                     Repeater {
0852                         model: Kube.MailListModel {
0853                             filter: {
0854                                 "entityId": componentRoot.parent ? componentRoot.parent.entityId : null,
0855                                 "headersOnly": true,
0856                                 "fetchMails": true
0857                             }
0858                         }
0859                         delegate: Column {
0860                             id: subHeadline
0861 
0862                             Kube.Label {
0863                                 text: qsTr("Account: %1").arg(accountName)
0864                                 color: Kube.Colors.disabledTextColor
0865                                 wrapMode: Text.Wrap
0866                             }
0867                             Kube.Label {
0868                                 text: qsTr("Subject: %1").arg(model.subject)
0869                                 color: Kube.Colors.disabledTextColor
0870                                 wrapMode: Text.Wrap
0871                             }
0872                             Kube.Label {
0873                                 text: qsTr("To: %1").arg(model.to)
0874                                 color: Kube.Colors.disabledTextColor
0875                                 wrapMode: Text.Wrap
0876                             }
0877                             Kube.Label {
0878                                 visible: !!model.cc
0879                                 text: qsTr("Cc: %1").arg(model.cc)
0880                                 color: Kube.Colors.disabledTextColor
0881                                 wrapMode: Text.Wrap
0882                             }
0883 
0884                         }
0885                     }
0886                 }
0887 
0888                 Kube.Button {
0889                     text: qsTr("Try Again")
0890                     onClicked: {
0891                         Kube.Fabric.postMessage(Kube.Messages.sendOutbox, {})
0892                     }
0893                 }
0894             }
0895         }
0896     }
0897 
0898     Component {
0899         id: transmissionSuccessComponent
0900         Item {
0901             id: componentRoot
0902             Column {
0903                 anchors {
0904                     top: parent.top
0905                     left: parent.left
0906                     right: parent.right
0907                 }
0908                 spacing: Kube.Units.largeSpacing
0909 
0910                 Kube.Heading {
0911                     id: heading
0912                     text: qsTr("Succeeded to send the message.")
0913                 }
0914 
0915                 Column {
0916                     spacing: Kube.Units.largeSpacing
0917 
0918                     Repeater {
0919                         model: Kube.MailListModel {
0920                             filter: {
0921                                 "entityId": componentRoot.parent ? componentRoot.parent.entityId : null,
0922                                 "headersOnly": true,
0923                                 "fetchMails": true
0924                             }
0925                         }
0926                         delegate: Column {
0927                             id: subHeadline
0928 
0929                             Kube.Label {
0930                                 text: qsTr("Account: %1").arg(accountName)
0931                                 color: Kube.Colors.disabledTextColor
0932                                 wrapMode: Text.Wrap
0933                             }
0934                             Kube.Label {
0935                                 text: qsTr("Subject: %1").arg(model.subject)
0936                                 color: Kube.Colors.disabledTextColor
0937                                 wrapMode: Text.Wrap
0938                             }
0939                             Kube.Label {
0940                                 text: qsTr("To: %1").arg(model.to)
0941                                 color: Kube.Colors.disabledTextColor
0942                                 wrapMode: Text.Wrap
0943                             }
0944                             Kube.Label {
0945                                 visible: !!model.cc
0946                                 text: qsTr("Cc: %1").arg(model.cc)
0947                                 color: Kube.Colors.disabledTextColor
0948                                 wrapMode: Text.Wrap
0949                             }
0950                         }
0951                     }
0952                 }
0953             }
0954         }
0955     }
0956     Component {
0957         id: conversationComponent
0958 
0959         Kube.ConversationView {
0960             id: componentRoot
0961 
0962             function mailFilter() {
0963                 return {
0964                     "mail": componentRoot.parent ? componentRoot.parent.itemData.mail : null,
0965                     "headersOnly": false,
0966                     "fetchMails": true,
0967                     //TODO hide trash in non-trash folders
0968                     //Don't hide trash in the trash folder
0969                     // "hideTrash": root.hideTrash,
0970                     // "hideNonTrash": root.hideNonTrash
0971                 }
0972             }
0973 
0974             objectName: "mailView"
0975             activeFocusOnTab: true
0976             model: Kube.MailListModel {
0977                 id: mailViewModel
0978                 filter: mailFilter()
0979             }
0980         }
0981     }
0982 
0983 
0984     Component {
0985         id: controllerComponent
0986         Kube.EventController {
0987         }
0988     }
0989     Component {
0990         id: eventComponent
0991         EventView {
0992             id: componentRoot
0993             property var occurrence: componentRoot.parent ? componentRoot.parent.itemData.occurrence : null
0994             onOccurrenceChanged: {
0995                 //Workaround because we need to create a new controller to reload the occurrence
0996                 componentRoot.controller = controllerComponent.createObject(parent, {"eventOccurrence": occurrence})
0997             }
0998         }
0999     }
1000 
1001     Component {
1002         id: configComponent
1003         Kube.ScrollablePopup {
1004             id: configPopup
1005 
1006             onAccepted: {
1007                 inboundModel.config = {
1008                     "folderNameBlacklist": folderNameBlacklist.text.split(', '),
1009                     "folderSpecialPurposeBlacklist": folderSpecialPurposeBlacklist.text.split(', '),
1010                     "perFolderMimeMessageWhitelistFilter": JSON.parse(perFolderMimeMessageWhitelistFilter.text),
1011                     "senderBlacklist": senderBlacklist.text.split(', '),
1012                     "toBlacklist": toBlacklist.text.split(', '),
1013                     "senderNameContainsFilter": senderNameContainsFilter.text,
1014                 };
1015                 configPopup.close()
1016             }
1017 
1018             GridLayout {
1019                 id: grid
1020                 width: parent.width
1021                 height: childrenRect.height
1022                 columns: 2
1023                 columnSpacing: Kube.Units.largeSpacing
1024                 rowSpacing: Kube.Units.largeSpacing
1025 
1026                 Kube.Label {
1027                     text: qsTr("Folder name blacklist")
1028                     Layout.alignment: Qt.AlignRight
1029                 }
1030                 Kube.TextField {
1031                     id: folderNameBlacklist
1032                     focus: true
1033                     Layout.fillWidth: true
1034                     placeholderText: qsTr("Comma separated folder names")
1035                     text: inboundModel.config.folderNameBlacklist.join(', ')
1036                 }
1037 
1038                 Kube.Label {
1039                     text: qsTr("Per Folder Mime Message Whitelist")
1040                     Layout.alignment: Qt.AlignRight
1041                 }
1042                 Kube.TextField {
1043                     id: perFolderMimeMessageWhitelistFilter
1044                     focus: true
1045                     Layout.fillWidth: true
1046                     placeholderText: JSON.stringify({"foldername1": "filterstring1", "foldername2": "filterstring2",})
1047                     text: JSON.stringify(inboundModel.config.perFolderMimeMessageWhitelistFilter)
1048                 }
1049 
1050                 Kube.Label {
1051                     text: qsTr("Folder special purpose blacklist")
1052                     Layout.alignment: Qt.AlignRight
1053                 }
1054                 Kube.TextField {
1055                     id: folderSpecialPurposeBlacklist
1056                     focus: true
1057                     Layout.fillWidth: true
1058                     placeholderText: qsTr("Comma separated special purpose types. Example: drafts, trash, sent")
1059                     text: inboundModel.config.folderSpecialPurposeBlacklist.join(', ')
1060                 }
1061 
1062                 Kube.Label {
1063                     text: qsTr("Sender blacklist")
1064                     Layout.alignment: Qt.AlignRight
1065                 }
1066                 Kube.TextField {
1067                     id: senderBlacklist
1068                     focus: true
1069                     Layout.fillWidth: true
1070                     placeholderText: qsTr("Comma separated sender email addresses")
1071                     text: inboundModel.config.senderBlacklist.join(', ')
1072                 }
1073 
1074                 Kube.Label {
1075                     text: qsTr("To blacklist")
1076                     Layout.alignment: Qt.AlignRight
1077                 }
1078                 Kube.TextField {
1079                     id: toBlacklist
1080                     focus: true
1081                     Layout.fillWidth: true
1082                     placeholderText: qsTr("Comma separated sender email addresses")
1083                     text: inboundModel.config.toBlacklist.join(', ')
1084                 }
1085 
1086                 Kube.Label {
1087                     text: qsTr("Sender name contains filter")
1088                     Layout.alignment: Qt.AlignRight
1089                 }
1090                 Kube.TextField {
1091                     id: senderNameContainsFilter
1092                     focus: true
1093                     Layout.fillWidth: true
1094                     placeholderText: qsTr("Comma separated sender email addresses")
1095                     text: inboundModel.config.senderNameContainsFilter
1096                 }
1097             }
1098         }
1099     }
1100 }