diff --git a/framework/qml/MailListView.qml b/framework/qml/MailListView.qml index cc68f003..55a3aaff 100644 --- a/framework/qml/MailListView.qml +++ b/framework/qml/MailListView.qml @@ -1,314 +1,315 @@ /* Copyright (C) 2016 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.7 import QtQuick.Controls 2.0 import QtQuick.Controls 1.4 as Controls import QtQuick.Layouts 1.1 import org.kube.framework 1.0 as Kube FocusScope { id: root //Private properties property variant parentFolder: null property bool isDraft : false property bool isImportant : false property bool isTrash : false property bool isUnread : false property variant currentMail: null property bool showFilter: false property string filter: null onFilterChanged: { Kube.Fabric.postMessage(Kube.Messages.searchString, {"searchString": filter}) } onParentFolderChanged: { currentMail = null filterField.clearSearch() } onShowFilterChanged: { find.forceActiveFocus() } Shortcut { sequence: StandardKey.Delete enabled: !isTrash onActivated: Kube.Fabric.postMessage(Kube.Messages.moveToTrash, {"mail":currentMail}) } Kube.Label { anchors.centerIn: parent visible: listView.count === 0 //TODO depending on whether we synchronized already or not the label should change. text: qsTr("Nothing here...") } ColumnLayout { anchors.fill: parent spacing: 0 Rectangle { id: filterField Layout.fillWidth: true height: Kube.Units.gridUnit * 2 color: Kube.Colors.buttonColor visible: root.showFilter function clearSearch() { root.showFilter = false find.text = "" root.filter = "" } RowLayout { anchors { verticalCenter: parent.verticalCenter } width: parent.width - Kube.Units.smallSpacing spacing: 0 Kube.IconButton { iconName: Kube.Icons.remove activeFocusOnTab: visible onClicked: filterField.clearSearch() } Kube.TextField { id: find Layout.fillWidth: true placeholderText: qsTr("Filter...") onTextChanged: root.filter = text activeFocusOnTab: visible focus: visible Keys.onEscapePressed: filterField.clearSearch() } } } Kube.ListView { id: listView objectName: "listView" Layout.fillWidth: true Layout.fillHeight: true clip: true focus: true //BEGIN keyboard nav onActiveFocusChanged: { if (activeFocus && currentIndex < 0) { currentIndex = 0 } } Keys.onDownPressed: { incrementCurrentIndex() } Keys.onUpPressed: { decrementCurrentIndex() } //END keyboard nav onCurrentItemChanged: { if (currentItem) { var currentData = currentItem.currentData; root.currentMail = currentData.mail; root.isDraft = currentData.draft; root.isTrash = currentData.trash; root.isImportant = currentData.important; root.isUnread = currentData.unread; if (currentData.mail && currentData.unread) { Kube.Fabric.postMessage(Kube.Messages.markAsRead, {"mail": currentData.mail}) } } } model: Kube.MailListModel { id: mailListModel parentFolder: root.parentFolder filter: root.filter } delegate: Kube.ListDelegate { id: delegateRoot //Required for D&D property var mail: model.mail width: listView.availableWidth height: Kube.Units.gridUnit * 5 color: Kube.Colors.viewBackgroundColor border.color: Kube.Colors.backgroundColor border.width: 1 states: [ State { name: "dnd" when: mouseArea.drag.active PropertyChanges {target: mouseArea; cursorShape: Qt.ClosedHandCursor} PropertyChanges {target: delegateRoot; x: x; y: y} PropertyChanges {target: delegateRoot; parent: root} PropertyChanges {target: delegateRoot; opacity: 0.7} PropertyChanges {target: delegateRoot; highlighted: true} } ] Drag.active: mouseArea.drag.active Drag.hotSpot.x: mouseArea.mouseX Drag.hotSpot.y: mouseArea.mouseY Drag.source: delegateRoot MouseArea { id: mouseArea anchors.fill: parent drag.target: parent onReleased: parent.Drag.drop() onClicked: delegateRoot.clicked() } Item { id: content anchors { fill: parent margins: Kube.Units.smallSpacing } property color unreadColor: (model.unread && !delegateRoot.highlighted) ? Kube.Colors.highlightColor : delegateRoot.textColor //TODO batch editing // Kube.CheckBox { // id: checkBox // // anchors.verticalCenter: parent.verticalCenter // visible: (checked || delegateRoot.hovered) && !mouseArea.drag.active // opacity: 0.9 // } Column { anchors { verticalCenter: parent.verticalCenter left: parent.left leftMargin: Kube.Units.largeSpacing // + checkBox.width } Kube.Label{ id: subject width: content.width - Kube.Units.gridUnit * 3 text: model.subject color: content.unreadColor maximumLineCount: 2 wrapMode: Text.WordWrap elide: Text.ElideRight } Kube.Label { id: sender text: model.senderName color: delegateRoot.textColor font.italic: true width: delegateRoot.width - Kube.Units.gridUnit * 3 elide: Text.ElideRight } } Kube.Label { id: date anchors { right: parent.right bottom: parent.bottom } visible: !delegateRoot.hovered text: Qt.formatDateTime(model.date, "dd MMM yyyy") font.italic: true color: Kube.Colors.disabledTextColor font.pointSize: Kube.Units.tinyFontSize } Kube.Label { id: threadCounter anchors.right: parent.right text: model.threadSize color: content.unreadColor visible: model.threadSize > 1 } } Row { id: buttons anchors { right: parent.right bottom: parent.bottom margins: Kube.Units.smallSpacing } visible: delegateRoot.hovered && !mouseArea.drag.active spacing: Kube.Units.smallSpacing opacity: 0.7 Kube.IconButton { id: readButton iconName: Kube.Icons.markAsRead visible: model.unread onClicked: Kube.Fabric.postMessage(Kube.Messages.markAsRead, {"mail": model.mail}) activeFocusOnTab: false } Kube.IconButton { id: unreadButton iconName: Kube.Icons.markAsUnread visible: !model.unread onClicked: Kube.Fabric.postMessage(Kube.Messages.markAsUnread, {"mail": model.mail}) activeFocusOnTab: false } Kube.IconButton { id: importantButton iconName: Kube.Icons.markImportant visible: !!model.mail onClicked: Kube.Fabric.postMessage(Kube.Messages.toggleImportant, {"mail": model.mail, "important": model.important}) activeFocusOnTab: false } Kube.IconButton { id: deleteButton + objectName: "deleteButton" iconName: Kube.Icons.moveToTrash visible: !!model.mail onClicked: Kube.Fabric.postMessage(Kube.Messages.moveToTrash, {"mail": model.mail}) activeFocusOnTab: false } Kube.IconButton { id: restoreButton iconName: Kube.Icons.undo visible: !!model.trash onClicked: Kube.Fabric.postMessage(Kube.Messages.restoreFromTrash, {"mail": model.mail}) activeFocusOnTab: false } } } } } } diff --git a/views/conversation/tests/tst_conversationview.qml b/views/conversation/tests/tst_conversationview.qml index 610c28b3..666114fd 100644 --- a/views/conversation/tests/tst_conversationview.qml +++ b/views/conversation/tests/tst_conversationview.qml @@ -1,120 +1,183 @@ /* * Copyright 2017 Christian Mollekopf * * This program 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, 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 Library General Public License for more details * * You should have received a copy of the GNU Library 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.7 import QtTest 1.0 import "../qml" import org.kube.framework 1.0 as Kube import org.kube.test 1.0 TestCase { id: testCase width: 400 height: 400 name: "MailView" Component { id: mailViewComponent View { focus: true } } function test_1start() { var mailView = createTemporaryObject(mailViewComponent, testCase, {}) verify(mailView) } function test_2verifyInitialFocus() { var mailView = createTemporaryObject(mailViewComponent, testCase, {}) var newMailButton = findChild(mailView, "newMailButton"); verify(newMailButton) // verify(newMailButton.activeFocus) } function test_3selectMessage() { var initialState = { accounts: [{ id: "account1", name: "Test Account" }], identities: [{ account: "account1", name: "Test Identity", address: "identity@example.org" }], resources: [{ id: "resource1", account: "account1", type: "dummy" }, { id: "resource2", account: "account1", type: "mailtransport" }], folders: [{ id: "folder1", resource: "resource1", name: "Folder 1", specialpurpose: ["inbox"], mails: [{ resource: "resource1", subject: "subject1", body: "body", to: ["to@example.org"], cc: ["cc@example.org"], bcc: ["bcc@example.org"], draft: true }, { resource: "resource1", subject: "subject2", body: "body", to: ["to@example.org"], cc: ["cc@example.org"], bcc: ["bcc@example.org"], draft: true } ], }], } TestStore.setup(initialState) var mailView = createTemporaryObject(mailViewComponent, testCase, {}) var folderListView = findChild(mailView, "folderListView"); verify(folderListView) var folder = TestStore.load("folder", {resource: "resource1"}) verify(folder) Kube.Fabric.postMessage(Kube.Messages.folderSelection, {"folder": folder, "trash": false}); var mailListView = findChild(mailView, "mailListView"); verify(mailListView) var listView = findChild(mailListView, "listView"); verify(listView) tryCompare(listView, "count", 2) var conversationView = findChild(mailView, "mailView"); verify(conversationView) var listView = findChild(conversationView, "listView"); verify(listView) - // tryCompare(listView, "count", 2) + } + + function test_4moveToTrash() { + var initialState = { + accounts: [{ + id: "account1", + name: "Test Account" + }], + identities: [{ + account: "account1", + name: "Test Identity", + address: "identity@example.org" + }], + resources: [{ + id: "resource1", + account: "account1", + type: "dummy" + }, + { + id: "resource2", + account: "account1", + type: "mailtransport" + }], + folders: [{ + id: "folder1", + resource: "resource1", + name: "Folder 1", + specialpurpose: ["inbox"], + mails: [{ + resource: "resource1", + subject: "subject1", + body: "body", + to: ["to@example.org"], + cc: ["cc@example.org"], + bcc: ["bcc@example.org"] + } + ], + }], + } + TestStore.setup(initialState) + var mailView = createTemporaryObject(mailViewComponent, testCase, {}) + var folderListView = findChild(mailView, "folderListView"); + verify(folderListView) + + var folder = TestStore.load("folder", {resource: "resource1"}) + verify(folder) + + Kube.Fabric.postMessage(Kube.Messages.folderSelection, {"folder": folder, "trash": false}); + + var mailListView = findChild(mailView, "mailListView"); + verify(mailListView) + var listView = findChild(mailListView, "listView"); + verify(listView) + tryCompare(listView, "count", 1) + + listView.currentIndex = 0 + var currentItem = listView.currentItem + verify(currentItem) + + var deleteButton = findChild(currentItem, "deleteButton"); + verify(deleteButton) + deleteButton.clicked() + + tryCompare(listView, "count", 0) } }