diff --git a/framework/qml/MailListView.qml b/framework/qml/MailListView.qml index 5d26465e..631107e6 100644 --- a/framework/qml/MailListView.qml +++ b/framework/qml/MailListView.qml @@ -1,292 +1,297 @@ /* 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.9 import QtQuick.Controls 2.0 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 alias filter: mailListModel.filter onParentFolderChanged: { currentMail = null } Kube.Listener { filter: Kube.Messages.selectNextConversation onMessageReceived: { listView.incrementCurrentIndex() listView.forceActiveFocus() } } Kube.Listener { filter: Kube.Messages.selectPreviousConversation onMessageReceived: { listView.decrementCurrentIndex() listView.forceActiveFocus() } } 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 Kube.ListView { id: listView objectName: "listView" Layout.fillWidth: true Layout.fillHeight: true clip: true focus: true onActiveFocusChanged: { if (activeFocus && currentIndex < 0) { currentIndex = 0 } } Keys.onPressed: { //Not implemented as a shortcut because we want it only to apply if we have the focus if (event.text == "d") { Kube.Fabric.postMessage(Kube.Messages.moveToTrash, {"mail": root.currentMail}) } else if (event.text == "r") { Kube.Fabric.postMessage(Kube.Messages.reply, {"mail": root.currentMail}) + } else if (event.text == "i") { + Kube.Fabric.postMessage(Kube.Messages.setImportant, {"mail": root.currentMail, "important": !currentItem.currentData.important}) + } else if (event.text == "u") { + Kube.Fabric.postMessage(Kube.Messages.markAsUnread, {"mail": root.currentMail}) } } 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 } delegate: Kube.ListDelegate { id: delegateRoot //Required for D&D property var mail: model.mail + property bool buttonsVisible: delegateRoot.hovered 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.2} 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.focused + visible: !delegateRoot.buttonsVisible text: Qt.formatDateTime(model.date, "dd MMM yyyy") font.italic: true color: delegateRoot.disabledTextColor font.pointSize: Kube.Units.tinyFontSize } Kube.Label { id: threadCounter anchors { right: parent.right margins: Kube.Units.smallSpacing } text: model.threadSize color: content.unreadColor - visible: model.threadSize > 1 && !delegateRoot.focused + visible: model.threadSize > 1 && !delegateRoot.buttonsVisible } } Kube.Icon { - anchors { - right: parent.right - verticalCenter: parent.verticalCenter - margins: Kube.Units.smallSpacing - } + anchors { + right: parent.right + verticalCenter: parent.verticalCenter + margins: Kube.Units.smallSpacing + } - visible: model.important && !delegateRoot.focused && !mouseArea.drag.active - iconName: Kube.Icons.isImportant + visible: model.important && !delegateRoot.buttonsVisible && !mouseArea.drag.active + iconName: Kube.Icons.isImportant } Column { id: buttons anchors { right: parent.right margins: Kube.Units.smallSpacing verticalCenter: parent.verticalCenter } - visible: delegateRoot.focused && !mouseArea.drag.active + visible: delegateRoot.buttonsVisible && !mouseArea.drag.active opacity: 0.7 Kube.IconButton { id: restoreButton iconName: Kube.Icons.undo visible: !!model.trash onClicked: Kube.Fabric.postMessage(Kube.Messages.restoreFromTrash, {"mail": model.mail}) activeFocusOnTab: false tooltip: qsTr("Restore from trash") } Kube.IconButton { id: readButton iconName: Kube.Icons.markAsRead visible: model.unread && !model.trash onClicked: Kube.Fabric.postMessage(Kube.Messages.markAsRead, {"mail": model.mail}) tooltip: qsTr("Mark as read") } Kube.IconButton { id: unreadButton iconName: Kube.Icons.markAsUnread visible: !model.unread && !model.trash onClicked: Kube.Fabric.postMessage(Kube.Messages.markAsUnread, {"mail": model.mail}) activeFocusOnTab: false tooltip: qsTr("Mark as unread") } Kube.IconButton { id: importantButton iconName: model.important ? Kube.Icons.markImportant : Kube.Icons.markUnimportant visible: !!model.mail onClicked: Kube.Fabric.postMessage(Kube.Messages.setImportant, {"mail": model.mail, "important": !model.important}) activeFocusOnTab: false tooltip: qsTr("Mark as important") } 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 tooltip: qsTr("Move to trash") } } } } } } diff --git a/views/conversation/qml/View.qml b/views/conversation/qml/View.qml index 1ca0348f..44208fa5 100644 --- a/views/conversation/qml/View.qml +++ b/views/conversation/qml/View.qml @@ -1,224 +1,226 @@ /* * Copyright (C) 2017 Michael Bohlender, * Copyright (C) 2017 Christian Mollekopf, * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import QtQuick 2.9 import QtQuick.Controls 1.3 as Controls1 import QtQuick.Controls 2 import QtQuick.Layouts 1.1 import org.kube.framework 1.0 as Kube Kube.View { id: root property alias currentAccount: accountFolderview.currentAccount //We have to hardcode because all the mapToItem/mapFromItem functions are garbage searchArea: Qt.rect(ApplicationWindow.window.sidebarWidth + mailListView.parent.x, 0, (mailView.x + mailView.width) - mailListView.parent.x, (mailView.y + mailView.height) - mailListView.y) onFilterChanged: { mailListView.filter = filter Kube.Fabric.postMessage(Kube.Messages.searchString, {"searchString": filter}) } Kube.Listener { filter: Kube.Messages.search onMessageReceived: root.triggerSearch() } helpViewComponent: Kube.HelpPopup { ListModel { ListElement { description: qsTr("Jump to next thread:"); shortcut: "j" } ListElement { description: qsTr("Jump to previous thread:"); shortcut: "k" } ListElement { description: qsTr("Jump to next message:"); shortcut: "n" } ListElement { description: qsTr("Jump to previous message:"); shortcut: "p" } ListElement { description: qsTr("Jump to next folder:"); shortcut: "f,n" } ListElement { description: qsTr("Jump to previous previous folder:"); shortcut: "f,p" } ListElement { description: qsTr("Compose new message:"); shortcut: "c" } ListElement { description: qsTr("Reply to the currently focused message:"); shortcut: "r" } ListElement { description: qsTr("Delete the currently focused message:"); shortcut: "d" } + ListElement { description: qsTr("Mark the currently focused message as important:"); shortcut: "i" } + ListElement { description: qsTr("Mark the currently focused message as unread:"); shortcut: "u" } ListElement { description: qsTr("Show this help text:"); shortcut: "?" } } } Shortcut { sequences: ['j'] onActivated: Kube.Fabric.postMessage(Kube.Messages.selectNextConversation, {}) } Shortcut { sequences: ['k'] onActivated: Kube.Fabric.postMessage(Kube.Messages.selectPreviousConversation, {}) } Shortcut { sequences: ['Shift+J'] onActivated: Kube.Fabric.postMessage(Kube.Messages.scrollConversationDown, {}) } Shortcut { sequences: ['Shift+K'] onActivated: Kube.Fabric.postMessage(Kube.Messages.scrollConversationUp, {}) } Shortcut { sequences: ['n'] onActivated: Kube.Fabric.postMessage(Kube.Messages.selectNextMessage, {}) } Shortcut { sequences: ['p'] onActivated: Kube.Fabric.postMessage(Kube.Messages.selectPreviousMessage, {}) } Shortcut { sequences: ['f,n'] onActivated: Kube.Fabric.postMessage(Kube.Messages.selectNextFolder, {}) } Shortcut { sequences: ['f,p'] onActivated: Kube.Fabric.postMessage(Kube.Messages.selectPreviousFolder, {}) } Shortcut { sequences: ['c'] onActivated: Kube.Fabric.postMessage(Kube.Messages.compose, {}) } Shortcut { sequence: "?" onActivated: root.showHelp() } Controls1.SplitView { anchors.fill: parent Rectangle { width: Kube.Units.gridUnit * 10 Layout.fillHeight: parent.height color: Kube.Colors.darkBackgroundColor Kube.PositiveButton { id: newMailButton objectName: "newMailButton" anchors { top: parent.top left: parent.left right: parent.right margins: Kube.Units.largeSpacing } focus: true text: qsTr("New Email") onClicked: Kube.Fabric.postMessage(Kube.Messages.compose, {}) } Kube.InlineAccountSwitcher { id: accountFolderview activeFocusOnTab: true anchors { top: newMailButton.bottom topMargin: Kube.Units.largeSpacing bottom: statusBarContainer.top left: newMailButton.left right: parent.right } } Item { id: statusBarContainer anchors { topMargin: Kube.Units.smallSpacing bottom: parent.bottom left: parent.left right: parent.right } height: childrenRect.height Rectangle { id: border visible: statusBar.visible anchors { right: parent.right left: parent.left margins: Kube.Units.smallSpacing } height: 1 color: Kube.Colors.viewBackgroundColor opacity: 0.3 } Kube.StatusBar { id: statusBar accountId: accountFolderview.currentAccount height: Kube.Units.gridUnit * 2 anchors { top: border.bottom left: statusBarContainer.left right: statusBarContainer.right } } } } Rectangle { width: Kube.Units.gridUnit * 18 Layout.fillHeight: parent.height color: "transparent" border.width: 1 border.color: Kube.Colors.buttonColor Kube.MailListView { id: mailListView objectName: "mailListView" anchors.fill: parent activeFocusOnTab: true Layout.minimumWidth: Kube.Units.gridUnit * 10 Kube.Listener { filter: Kube.Messages.folderSelection onMessageReceived: { root.clearSearch() mailListView.parentFolder = message.folder } } onCurrentMailChanged: { Kube.Fabric.postMessage(Kube.Messages.mailSelection, {"mail": currentMail}) } } } Kube.ConversationView { id: mailView objectName: "mailView" Layout.fillWidth: true Layout.fillHeight: parent.height activeFocusOnTab: true model: Kube.MailListModel { id: mailViewModel } Kube.Listener { filter: Kube.Messages.mailSelection onMessageReceived: { mailViewModel.mail = message.mail } } Kube.Listener { filter: Kube.Messages.folderSelection onMessageReceived: { mailView.hideTrash = !message.trash mailView.hideNonTrash = message.trash } } } } }