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 }