From d9295fc8f19e4005f8454e7f193f80316550ac0c Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Tue, 4 Apr 2017 19:19:41 +0200 Subject: One framework plugin to rule them all --- framework/CMakeLists.txt | 3 + framework/accounts/qmldir | 4 - framework/actions/qmldir | 3 - framework/domain/qmldir | 3 - framework/notifications/qmldir | 3 - framework/qml/AccountSwitcher.qml | 215 ++++++++++++ framework/qml/AttachmentDelegate.qml | 68 ++++ framework/qml/AutocompleteLineEdit.qml | 143 ++++++++ framework/qml/Avatar.qml | 57 ++++ framework/qml/Button.qml | 57 ++++ framework/qml/ConversationView.qml | 574 +++++++++++++++++++++++++++++++++ framework/qml/EditAccount.qml | 138 ++++++++ framework/qml/EditAccountDialog.qml | 38 +++ framework/qml/FocusComposer.qml | 252 +++++++++++++++ framework/qml/FolderListView.qml | 195 +++++++++++ framework/qml/Icon.qml | 48 +++ framework/qml/ListItem.qml | 64 ++++ framework/qml/MailListView.qml | 292 +++++++++++++++++ framework/qml/MailViewer.qml | 76 +++++ framework/qml/Notification.qml | 83 +++++ framework/qml/Outbox.qml | 151 +++++++++ framework/qml/OverlayDialog.qml | 64 ++++ framework/qml/People.qml | 435 +++++++++++++++++++++++++ framework/qml/PositiveButton.qml | 47 +++ framework/qmldir | 23 ++ framework/settings/qmldir | 3 - 26 files changed, 3023 insertions(+), 16 deletions(-) delete mode 100644 framework/accounts/qmldir delete mode 100644 framework/actions/qmldir delete mode 100644 framework/domain/qmldir delete mode 100644 framework/notifications/qmldir create mode 100644 framework/qml/AccountSwitcher.qml create mode 100644 framework/qml/AttachmentDelegate.qml create mode 100644 framework/qml/AutocompleteLineEdit.qml create mode 100644 framework/qml/Avatar.qml create mode 100644 framework/qml/Button.qml create mode 100644 framework/qml/ConversationView.qml create mode 100644 framework/qml/EditAccount.qml create mode 100644 framework/qml/EditAccountDialog.qml create mode 100644 framework/qml/FocusComposer.qml create mode 100644 framework/qml/FolderListView.qml create mode 100644 framework/qml/Icon.qml create mode 100644 framework/qml/ListItem.qml create mode 100644 framework/qml/MailListView.qml create mode 100644 framework/qml/MailViewer.qml create mode 100644 framework/qml/Notification.qml create mode 100644 framework/qml/Outbox.qml create mode 100644 framework/qml/OverlayDialog.qml create mode 100644 framework/qml/People.qml create mode 100644 framework/qml/PositiveButton.qml create mode 100644 framework/qmldir delete mode 100644 framework/settings/qmldir (limited to 'framework') diff --git a/framework/CMakeLists.txt b/framework/CMakeLists.txt index d14360b4..f097f658 100644 --- a/framework/CMakeLists.txt +++ b/framework/CMakeLists.txt @@ -33,6 +33,9 @@ enable_testing() set(SINK_RESOURCE_PLUGINS_PATH ${QT_PLUGIN_INSTALL_DIR}/sink/resources) +install(FILES qmldir DESTINATION ${QML_INSTALL_DIR}/org/kube/framework) +install(DIRECTORY qml DESTINATION ${QML_INSTALL_DIR}/org/kube/framework) + # The actions framework add_subdirectory(actions) # The settings framework diff --git a/framework/accounts/qmldir b/framework/accounts/qmldir deleted file mode 100644 index 662725de..00000000 --- a/framework/accounts/qmldir +++ /dev/null @@ -1,4 +0,0 @@ -module org.kube.framework.accounts - -plugin accountsplugin - diff --git a/framework/actions/qmldir b/framework/actions/qmldir deleted file mode 100644 index f6dccbda..00000000 --- a/framework/actions/qmldir +++ /dev/null @@ -1,3 +0,0 @@ -module org.kube.framework.actions - -plugin actionplugin diff --git a/framework/domain/qmldir b/framework/domain/qmldir deleted file mode 100644 index 54a3a98b..00000000 --- a/framework/domain/qmldir +++ /dev/null @@ -1,3 +0,0 @@ -module org.kube.framework.domain - -plugin mailplugin diff --git a/framework/notifications/qmldir b/framework/notifications/qmldir deleted file mode 100644 index 4eaad10c..00000000 --- a/framework/notifications/qmldir +++ /dev/null @@ -1,3 +0,0 @@ -module org.kube.framework.notifications - -plugin notificationplugin diff --git a/framework/qml/AccountSwitcher.qml b/framework/qml/AccountSwitcher.qml new file mode 100644 index 00000000..0cd91adc --- /dev/null +++ b/framework/qml/AccountSwitcher.qml @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2017 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.4 +import QtQuick.Layouts 1.1 +import QtQuick.Controls 2.0 as Controls2 +import QtQuick.Controls 1.4 as Controls + +import QtQml 2.2 as QtQml + +import org.kde.kirigami 1.0 as Kirigami + +import org.kube.framework.domain 1.0 as KubeFramework +import org.kube.framework.accounts 1.0 as KubeAccounts +import org.kube.components 1.0 as KubeComponents +import org.kube.components.theme 1.0 as KubeTheme + +Controls.ToolButton { + id: accountSwitcher + + property variant accountId + property variant accountName + + width: parent.width + + KubeFramework.FolderController { + id: folderController + accountId: accountId + } + + KubeAccounts.AccountsModel { + id: accountsModel + } + + + onClicked: { + popup.open() + } + + Controls2.Popup { + id: popup + + height: listView.count == 0 ? Kirigami.Units.gridUnit * 4 : Kirigami.Units.gridUnit * 2 + listView.count * Kirigami.Units.gridUnit * 3 + width: Kirigami.Units.gridUnit * 20 + + y: accountSwitcher.height + + modal: true + focus: true + closePolicy: Controls2.Popup.CloseOnEscape | Controls2.Popup.CloseOnPressOutsideParent + + Item { + id: buttons + anchors { + bottom: parent.bottom + } + + height: Kirigami.Units.gridUnit * 2 + width: parent.width + + Controls2.Button { + anchors { + left: parent.left + bottom: parent.bottom + } + + //iconName: "view-refresh" + text: "Sync" + enabled: folderController.synchronizeAction.enabled + onClicked: { + folderController.synchronizeAction.execute() + popup.close() + } + } + + KubeComponents.PositiveButton { + id: newAccountButton + + anchors { + right: parent.right + bottom: parent.bottom + } + + text: "Create new Account" + + onClicked: { + accountWizard.open() + popup.close() + } + } + } + + ListView { + id: listView + + anchors { + top: parent.top + bottom: buttons.top + left: parent.left + right: parent.right + } + + clip: true + + model: accountsModel + + delegate: Kirigami.AbstractListItem { + id: accountDelegate + + height: Kirigami.Units.gridUnit * 2 + + enabled: true + supportsMouseEvents: true + + checked: listView.currentIndex == index + onClicked: { + listView.currentIndex = model.index + popup.close() + } + Item { + height: Kirigami.Units.gridUnit + Kirigami.Units.smallSpacing * 1 + width: listView.width + + QtQml.Binding { + target: accountSwitcher + property: "accountId" + when: listView.currentIndex == index + value: model.accountId + } + + QtQml.Binding { + target: accountSwitcher + property: "accountName" + when: listView.currentIndex == index + value: model.name + } + + RowLayout { + anchors { + verticalCenter: parent.verticalCenter + left: parent.left + margins: Kirigami.Units.smallSpacing + } + + Layout.fillHeight: true + + Controls2.Label { + text: model.name + } + + Controls.ToolButton { + id: statusIcon + visible: false + iconName: "" + enabled: false + states: [ + State { + name: "busy"; when: model.status == KubeAccountsFramework.AccountsModel.BusyStatus + PropertyChanges { target: statusIcon; iconName: KubeTheme.Icons.busy; visible: true } + }, + State { + name: "error"; when: model.status == KubeAccountsFramework.AccountsModel.ErrorStatus + PropertyChanges { target: statusIcon; iconName: KubeTheme.Icons.error; visible: true } + }, + State { + name: "checkmark"; when: model.status == KubeAccountsFramework.AccountsModel.ConnectedStatus + PropertyChanges { target: statusIcon; iconName: KubeTheme.Icons.connected; visible: true } + } + ] + } + } + Controls2.Button { + + anchors { + right: parent.right + rightMargin: Kirigami.Units.largeSpacing + verticalCenter: parent.verticalCenter + } + + opacity: hovered ? 1 : 0.7 + visible: accountDelegate.containsMouse + text: "edit" + + onClicked: { + editAccountComponent.createObject(app, {accountId:model.accountId}) + popup.close() + } + + Component { + id: editAccountComponent + KubeComponents.EditAccountDialog { + anchors.fill: parent + } + } + } + } + } + } + } +} diff --git a/framework/qml/AttachmentDelegate.qml b/framework/qml/AttachmentDelegate.qml new file mode 100644 index 00000000..a589c9f3 --- /dev/null +++ b/framework/qml/AttachmentDelegate.qml @@ -0,0 +1,68 @@ +/* + * 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.Layouts 1.1 +import org.kde.kirigami 1.0 as Kirigami +import org.kube.components.theme 1.0 as KubeTheme + +Item { + id: root + + property string name + property string icon + + width: content.width + Kirigami.Units.gridUnit / 2 + height: content.height + Kirigami.Units.gridUnit / 2 + + Rectangle { + anchors.fill: parent + + id: background + color: KubeTheme.Colors.disabledTextColor + } + + RowLayout { + id: content + + anchors.centerIn: parent + + spacing: Kirigami.Units.smallSpacing + + Rectangle { + id: mimetype + + height: Kirigami.Units.gridUnit + width: Kirigami.Units.gridUnit + + color: KubeTheme.Colors.backgroundColor + + Kirigami.Icon { + height: parent.height + width: height + + source: root.icon + } + } + + Text { + text: root.name + color: KubeTheme.Colors.backgroundColor + } + } +} diff --git a/framework/qml/AutocompleteLineEdit.qml b/framework/qml/AutocompleteLineEdit.qml new file mode 100644 index 00000000..64e5940f --- /dev/null +++ b/framework/qml/AutocompleteLineEdit.qml @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2016 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.7 +import QtQuick.Controls 2.0 as Controls2 +import QtQuick.Layouts 1.1 + +import org.kde.kirigami 1.0 as Kirigami +import org.kube.components.theme 1.0 as KubeTheme + +Controls2.TextField { + id: textField + + property string searchTerm + property variant model + onTextChanged: { + if (text.length >= 2) { + searchTerm = text + startCompleting() + } else { + searchTerm = "" + abort() + } + } + Keys.onDownPressed: { + listView.incrementCurrentIndex() + } + Keys.onUpPressed: { + listView.decrementCurrentIndex() + } + Keys.onRightPressed: { + startCompleting() + } + Keys.onTabPressed: { + if (popup.visible) { + listView.incrementCurrentIndex() + } else { + event.accepted = false + } + } + Keys.onReturnPressed: { + accept() + } + Keys.onEscapePressed: { + abort() + } + + function startCompleting() { + if (!popup.visible) { + popup.open() + listView.currentIndex = -1 + } + } + + function accept() { + textField.text = listView.currentItem.text; + popup.close() + } + + function abort() { + popup.close() + } + + Controls2.Popup { + id: popup + x: 0 + y: textField.y + textField.height + padding: 0 + contentWidth: rect.width + contentHeight: rect.height + + Rectangle { + id: rect + + anchors.top: popup.top + anchors.left: popup.left + + height: listView.contentHeight + width: textField.width + + border.color: KubeTheme.Colors.textColor + color: KubeTheme.Colors.backgroundColor + + radius: 5 + ListView { + id: listView + height: childrenRect.height + width: parent.width + interactive: true + model: textField.model + delegate: Kirigami.AbstractListItem { + id: listDelegate + property string text: model.text + + width: listView.width + height: textField.height + + enabled: true + supportsMouseEvents: true + + checked: listView.currentIndex == index + onClicked: { + listView.currentIndex = model.index + accept() + } + + //Content + Item { + width: parent.width + height: parent.height + + Column { + anchors { + verticalCenter: parent.verticalCenter + left: parent.left + } + + Text{ + text: model.text + color: listDelegate.checked ? KubeTheme.Colors.highlightedTextColor : KubeTheme.Colors.textColor + } + } + } + } + } + } + } +} diff --git a/framework/qml/Avatar.qml b/framework/qml/Avatar.qml new file mode 100644 index 00000000..0a7c4c18 --- /dev/null +++ b/framework/qml/Avatar.qml @@ -0,0 +1,57 @@ +/* + 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.Layouts 1.1 + + +Rectangle { + + property string name; + + //colors taken from https://techbase.kde.org/Projects/Usability/HIG/Color + function calcColor(x) + { + switch (x % 5) { + case 0: + return "#16a085" + case 1: + return "#27ae60" + case 2: + return "#2980b9" + case 3: + return "#8e44ad" + case 4: + return "#c0392b" + } + } + + radius: 100 + + color: calcColor(name.length) + + Text { + anchors.centerIn: parent + + text: name.charAt(0) + + color: "#ecf0f1" + + font.capitalization: Font.AllUppercase + } +} diff --git a/framework/qml/Button.qml b/framework/qml/Button.qml new file mode 100644 index 00000000..948312b0 --- /dev/null +++ b/framework/qml/Button.qml @@ -0,0 +1,57 @@ +/* + * 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.7 +import org.kube.components.theme 1.0 as KubeTheme + +Rectangle { + id: root + + signal clicked() + property alias text: text.text + property color textColor: KubeTheme.Colors.highlightedTextColor + property string iconName: "" + property alias implicitHeight: content.implicitHeight + property alias implicitWidth: content.implicitWidth + width: implicitWidth + height: implicitHeight + + clip: true + + Row { + id: content + anchors.centerIn: parent + spacing: KubeTheme.Units.smallSpacing + Text { + id: text + anchors.verticalCenter: parent.verticalCenter + color: root.textColor + } + Icon { + id: icon + anchors.verticalCenter: parent.verticalCenter + iconName: root.iconName + visible: iconName != "" + } + } + + MouseArea { + anchors.fill: parent + onClicked: root.clicked() + } +} diff --git a/framework/qml/ConversationView.qml b/framework/qml/ConversationView.qml new file mode 100644 index 00000000..4196ebbd --- /dev/null +++ b/framework/qml/ConversationView.qml @@ -0,0 +1,574 @@ +/* + * 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 1.3 as Controls1 +import QtQuick.Controls 2 +import QtQuick.Layouts 1.1 +import org.kde.kirigami 1.0 as Kirigami + +import QtQml 2.2 as QtQml + +import org.kube.framework.domain 1.0 as KubeFramework +import org.kube.framework.actions 1.0 as KubeAction + +import org.kube.components.theme 1.0 as KubeTheme + +Rectangle { + id: root + + property variant mail; + property int currentIndex: 0; + property bool scrollToEnd: true; + property variant currentMail: null; + onCurrentIndexChanged: { + markAsReadTimer.restart(); + } + onMailChanged: { + scrollToEnd = true; + currentMail = null; + } + + color: KubeTheme.Colors.backgroundColor + + ListView { + id: listView + function setCurrentIndex() + { + /** + * This will detect the index at the "scrollbar-position" (visibleArea.yPosition). + * This ensures that the first and last entry can become the currentIndex, + * but in the middle of the list the item in the middle is set as the current item. + */ + var yPos = 0.5; + if (listView.visibleArea.yPosition < 0.4) { + yPos = 0.2 + (0.2 * listView.visibleArea.yPosition); + } + if (listView.visibleArea.yPosition > 0.6) { + yPos = 0.6 + (0.2 * listView.visibleArea.yPosition) + } + var indexAtCenter = listView.indexAt(root.width / 2, contentY + root.height * yPos); + if (indexAtCenter >= 0) { + root.currentIndex = indexAtCenter; + } else { + root.currentIndex = count - 1; + } + } + + anchors { + top: parent.top + left: parent.left + right: parent.right + bottom: parent.bottom + } + + clip: true + + model: KubeFramework.MailListModel { + mail: root.mail + } + + header: Item { + height: KubeTheme.Units.gridUnit * 0.5 + width: parent.width + + } + + footer: Item { + height: KubeTheme.Units.gridUnit + width: parent.width + } + + delegate: mailDelegate + + //Setting the currentIndex results in further lags. So we don't do that either. + // currentIndex: root.currentIndex + + boundsBehavior: Flickable.StopAtBounds + + //default is 1500, which is not usable with a mouse + flickDeceleration: 10000 + + //Optimize for view quality + pixelAligned: true + + Timer { + id: scrollToEndTimer + interval: 10 + running: false + repeat: false + onTriggered: { + //Only do this once per conversation + root.scrollToEnd = false; + root.currentIndex = listView.count - 1 + //positionViewAtEnd/Index don't work + listView.contentY = Math.max(listView.contentHeight - listView.height, 0) + } + } + + onCountChanged: { + if (root.scrollToEnd) { + scrollToEndTimer.restart() + } + } + + onContentHeightChanged: { + //Initially it will resize a lot, so we keep waiting + if (root.scrollToEnd) { + scrollToEndTimer.restart() + } + } + + onContentYChanged: { + //We have to track our current mail manually + setCurrentIndex(); + } + + //The cacheBuffer needs to be large enough to fit the whole thread. + //Otherwise the contentHeight will constantly increase and decrease, + //which will break lot's of things. + cacheBuffer: 100000 + + KubeFramework.MailController { + id: mailController + Binding on mail { + //!! checks for the availability of the type + when: !!root.currentMail + value: root.currentMail + } + } + + Timer { + id: markAsReadTimer + interval: 2000 + running: false + repeat: false + onTriggered: { + if (mailController.markAsReadAction.enabled) { + mailController.markAsReadAction.execute(); + } + } + } + + //Intercept all scroll events, + //necessary due to the webengineview + KubeFramework.MouseProxy { + anchors.fill: parent + target: listView + forwardWheelEvents: true + } + } + Component { + id: mailDelegate + + Item { + id: wrapper + property bool isCurrent: root.currentIndex === index; + onIsCurrentChanged: { + if (isCurrent) { + root.currentMail = model.mail + } + } + + height: sheet.height + KubeTheme.Units.gridUnit + width: parent.width + + Rectangle { + id: sheet + anchors.centerIn: parent + implicitHeight: header.height + attachments.height + body.height + incompleteBody.height + footer.height + KubeTheme.Units.largeSpacing + width: parent.width - KubeTheme.Units.gridUnit * 2 + + //Overlay for non-active mails + Rectangle { + anchors.fill: parent + visible: !wrapper.isCurrent + color: "lightGrey" + z: 1 + opacity: 0.2 + } + + color: KubeTheme.Colors.viewBackgroundColor + + //BEGIN header + Item { + id: header + + anchors { + top: parent.top + left: parent.left + right: parent.right + margins: KubeTheme.Units.largeSpacing + } + + height: headerContent.height + KubeTheme.Units.smallSpacing + + states: [ + State { + name: "small" + PropertyChanges { target: subject; wrapMode: Text.NoWrap} + PropertyChanges { target: recipients; visible: true} + PropertyChanges { target: to; visible: false} + PropertyChanges { target: cc; visible: false} + PropertyChanges { target: bcc; visible: false} + }, + State { + name: "details" + PropertyChanges { target: subject; wrapMode: Text.WrapAnywhere} + PropertyChanges { target: recipients; visible: false} + PropertyChanges { target: to; visible: true} + PropertyChanges { target: cc; visible: true} + PropertyChanges { target: bcc; visible: true} + } + ] + + state: "small" + + Text { + id: date_label + + anchors { + right: seperator.right + top: parent.top + } + + text: Qt.formatDateTime(model.date, "dd MMM yyyy hh:mm") + + font.pointSize: Kirigami.Theme.defaultFont.pointSize * 0.7 + color: KubeTheme.Colors.textColor + opacity: 0.75 + } + + Column { + id: headerContent + + anchors { + //left: to_l.right + horizontalCenter: parent.horizontalCenter + } + + //spacing: KubeTheme.Units.smallSpacing + + width: parent.width + + Row{ + id: from + + width: parent.width + + spacing: KubeTheme.Units.smallSpacing + clip: true + + Text { + id: senderName + + text: model.senderName + + font.weight: Font.DemiBold + color: KubeTheme.Colors.textColor + opacity: 0.75 + } + + Text { + + text: model.sender + + width: parent.width - senderName.width - date_label.width - KubeTheme.Units.largeSpacing + elide: Text.ElideRight + + color: KubeTheme.Colors.textColor + opacity: 0.75 + + clip: true + } + } + + Text { + id: subject + + width: to.width + + text: model.subject + + elide: Text.ElideRight + + color: KubeTheme.Colors.textColor + opacity: 0.75 + font.italic: true + } + + Text { + id: recipients + + width: parent.width - goDown.width - KubeTheme.Units.smallSpacing + + text:"to: "+ model.to + " " + model.cc + " " + model.bcc + + elide: Text.ElideRight + + color: KubeTheme.Colors.textColor + opacity: 0.75 + } + + Text { + id: to + + width: parent.width - goDown.width - KubeTheme.Units.smallSpacing + + text:"to: " + model.to + + wrapMode: Text.WordWrap + color: KubeTheme.Colors.textColor + opacity: 0.75 + } + + Text { + id: cc + + width: parent.width - goDown.width - KubeTheme.Units.smallSpacing + + text:"cc: " + model.cc + + wrapMode: Text.WordWrap + color: KubeTheme.Colors.textColor + opacity: 0.75 + } + + Text { + id: bcc + + width: parent.width - goDown.width - KubeTheme.Units.smallSpacing + + text:"bcc: " + model.bcc + + wrapMode: Text.WordWrap + color: KubeTheme.Colors.textColor + opacity: 0.75 + } + + } + Rectangle { + id: goDown + anchors { + bottom: seperator.top + right: seperator.right + } + + height: KubeTheme.Units.gridUnit + width: height + + color: KubeTheme.Colors.backgroundColor + + Controls1.ToolButton { + anchors.fill: parent + + iconName: KubeTheme.Icons.goDown + } + } + + Rectangle { + anchors { + bottom: seperator.top + right: seperator.right + } + + height: KubeTheme.Units.gridUnit + width: height + + color: KubeTheme.Colors.backgroundColor + + Controls1.ToolButton { + anchors.fill: parent + + iconName: header.state === "details" ? KubeTheme.Icons.goUp : KubeTheme.Icons.goDown + + onClicked: { + header.state === "details" ? header.state = "small" : header.state = "details" + } + } + } + + Rectangle { + id: seperator + + anchors { + left: parent.left + right: parent.right + bottom: parent.bottom + } + + height: 1 + + color: KubeTheme.Colors.textColor + opacity: 0.5 + } + } + //END header + + Flow { + id: attachments + + anchors { + top: header.bottom + topMargin: KubeTheme.Units.smallSpacing + right: header.right + } + + width: header.width - KubeTheme.Units.largeSpacing + + layoutDirection: Qt.RightToLeft + spacing: KubeTheme.Units.smallSpacing + clip: true + + Repeater { + model: body.attachments + + delegate: AttachmentDelegate { + name: model.name + icon: "mail-attachment" + + clip: true + + //TODO size encrypted signed type + } + } + } + + MailViewer { + id: body + + anchors { + top: header.bottom + left: header.left + right: header.right + leftMargin: KubeTheme.Units.largeSpacing + rightMargin: KubeTheme.Units.largeSpacing + topMargin: Math.max(attachments.height, KubeTheme.Units.largeSpacing) + } + + width: header.width - KubeTheme.Units.largeSpacing * 2 + height: desiredHeight + + message: model.mimeMessage + visible: !model.incomplete + } + + Label { + id: incompleteBody + anchors { + top: header.bottom + left: header.left + right: header.right + leftMargin: KubeTheme.Units.largeSpacing + rightMargin: KubeTheme.Units.largeSpacing + topMargin: Math.max(attachments.height, KubeTheme.Units.largeSpacing) + } + visible: model.incomplete + text: "Incomplete body..." + color: KubeTheme.Colors.textColor + enabled: false + states: [ + State { + name: "inprogress"; when: model.status == KubeFramework.MailListModel.InProgressStatus + PropertyChanges { target: incompleteBody; text: "Downloading message..." } + }, + State { + name: "error"; when: model.status == KubeFramework.MailListModel.ErrorStatus + PropertyChanges { target: incompleteBody; text: "Failed to download message..." } + } + ] + } + Item { + id: footer + + anchors.bottom: parent.bottom + + height: KubeTheme.Units.gridUnit * 2 + width: parent.width + + Text { + anchors{ + verticalCenter: parent.verticalCenter + left: parent.left + leftMargin: KubeTheme.Units.largeSpacing + } + + KubeFramework.MailController { + id: mailController + mail: model.mail + } + + text: model.trash ? qsTr("Delete Mail") : qsTr("Move to trash") + color: KubeTheme.Colors.textColor + opacity: 0.5 + enabled: model.trash ? mailController.removeAction.enabled : mailController.moveToTrashAction.enabled + MouseArea { + anchors.fill: parent + enabled: parent.enabled + onClicked: { + if (model.trash) { + mailController.removeAction.execute(); + } else { + mailController.moveToTrashAction.execute(); + } + } + } + } + + Controls1.ToolButton { + visible: !model.trash + anchors{ + verticalCenter: parent.verticalCenter + right: parent.right + rightMargin: KubeTheme.Units.largeSpacing + } + + KubeAction.Context { + id: mailcontext + property variant mail + property bool isDraft + mail: model.mail + isDraft: model.draft + } + + KubeAction.Action { + id: replyAction + actionId: "org.kde.kube.actions.reply" + context: maillistcontext + } + + KubeAction.Action { + id: editAction + actionId: "org.kde.kube.actions.edit" + context: maillistcontext + } + + iconName: model.draft ? KubeTheme.Icons.edit : KubeTheme.Icons.replyToSender + onClicked: { + if (model.draft) { + editAction.execute() + } else { + replyAction.execute() + } + } + } + } + } + } + } +} diff --git a/framework/qml/EditAccount.qml b/framework/qml/EditAccount.qml new file mode 100644 index 00000000..8618ec91 --- /dev/null +++ b/framework/qml/EditAccount.qml @@ -0,0 +1,138 @@ +/* + * Copyright (C) 2016 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.7 +import QtQuick.Layouts 1.1 +import QtQuick.Controls 1.4 as Controls +import QtQuick.Controls 2.0 as Controls2 +import org.kde.kirigami 1.0 as Kirigami + +import org.kube.framework.accounts 1.0 as KubeAccounts +import org.kube.components.theme 1.0 as KubeTheme + +Item { + id: root + property string accountId + + KubeAccounts.AccountFactory { + id: accountFactory + accountId: root.accountId + } + + Item { + + anchors { + fill: parent + margins: Kirigami.Units.largeSpacing * 2 + } + + Kirigami.Heading { + id: heading + text: loader.item.heading + color: KubeTheme.Colors.highlightColor + } + + Kirigami.Label { + id: subHeadline + + anchors { + left: heading.left + top: heading.bottom + } + + width: parent.width + text: loader.item.subheadline + color: KubeTheme.Colors.disabledTextColor + wrapMode: Text.Wrap + } + + Item { + id: accountEdit + anchors { + top:subHeadline.bottom + left: parent.left + right: parent.right + topMargin: Kirigami.Units.largeSpacing * 2 + } + + Loader { + id: loader + anchors.fill: parent + source: accountFactory.uiPath + onLoaded: item.accountId = root.accountId + } + } + + Item { + id: spacer + Layout.fillHeight: true + anchors { + top:accountEdit.bottom + left: parent.left + right: parent.right + } + } + + //This is where we should place the account wizard ui + GridLayout { + id: footer + anchors { + top:spacer.bottom + bottom: parent.bottom + left: parent.left + right: parent.right + topMargin: Kirigami.Units.largeSpacing * 2 + } + + columns: 2 + columnSpacing: Kirigami.Units.largeSpacing + rowSpacing: Kirigami.Units.largeSpacing + + Item { + Layout.fillHeight: true + } + + Kirigami.Label { + text: "" + } + + Item { + Layout.fillWidth: true + + Controls.Button { + text: "Discard" + + onClicked: { + loader.item.remove() + dialog.closeDialog() + } + } + + Controls.Button { + anchors.right: parent.right + text: "Save" + onClicked: { + loader.item.save() + dialog.closeDialog() + } + } + } + } + } +} diff --git a/framework/qml/EditAccountDialog.qml b/framework/qml/EditAccountDialog.qml new file mode 100644 index 00000000..a7461640 --- /dev/null +++ b/framework/qml/EditAccountDialog.qml @@ -0,0 +1,38 @@ +/* + 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.4 +import QtQuick.Layouts 1.1 + +import org.kde.kirigami 1.0 as Kirigami + +import org.kube.components 1.0 as KubeComponents + +KubeComponents.OverlayDialog { + id: dialog + + property variant accountId + EditAccount { + accountId: dialog.accountId + + anchors.centerIn: parent + + height: dialog.height * 0.8 + width: dialog.width * 0.8 + } +} diff --git a/framework/qml/FocusComposer.qml b/framework/qml/FocusComposer.qml new file mode 100644 index 00000000..902309a8 --- /dev/null +++ b/framework/qml/FocusComposer.qml @@ -0,0 +1,252 @@ +/* + * 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.4 +import QtQuick.Layouts 1.1 +import QtQuick.Controls 2.0 as Controls2 + +import org.kde.kirigami 1.0 as Kirigami + +import org.kube.framework.domain 1.0 as KubeFramework + +Controls2.Popup { + id: root + + //Controller + KubeFramework.ComposerController { + id: composerController + onDone: { + clear(); + root.close() + } + } + + //actions + property variant sendAction: composerController.sendAction + property variant saveAsDraftAction: composerController.saveAsDraftAction + + //BEGIN functions + function loadMessage(message, loadAsDraft) { + composerController.loadMessage(message, loadAsDraft) + } + //END functions + + modal: true + focus: true + closePolicy: Controls2.Popup.CloseOnEscape | Controls2.Popup.CloseOnPressOutsideParent + + Item { + + height: parent.height + width: parent.width + + ColumnLayout { + + anchors { + fill: parent + margins: Kirigami.Units.largeSpacing + } + + ColumnLayout { + + anchors.fill: parent + + GridLayout { + + columns: 2 + + Controls2.Label { + Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + text: "To" + } + + AutocompleteLineEdit { + id: to + + Layout.fillWidth: true + + text: composerController.to + onTextChanged: { + composerController.to = text; + } + + model: composerController.recipientCompleter.model + onSearchTermChanged: { + composerController.recipientCompleter.searchString = searchTerm + } + } + + + Controls2.Label { + Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + text: "Cc" + visible: cc.visible + } + + AutocompleteLineEdit { + id: cc + + Layout.fillWidth: true + + visible: false + + text: composerController.cc + + onTextChanged: { + composerController.cc = text; + } + + model: composerController.recipientCompleter.model + onSearchTermChanged: { + composerController.recipientCompleter.searchString = searchTerm + } + } + + Controls2.Label { + Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + text: "Bcc" + visible: bcc.visible + } + + AutocompleteLineEdit { + id: bcc + + Layout.fillWidth: true + + visible : false + + text: composerController.bcc + + onTextChanged: { + composerController.bcc = text; + } + + model: composerController.recipientCompleter.model + onSearchTermChanged: { + composerController.recipientCompleter.searchString = searchTerm + } + } + + Controls2.Label { + text: "From" + } + + RowLayout { + + Controls2.ComboBox { + id: identityCombo + model: composerController.identitySelector.model + textRole: "displayName" + + Layout.fillWidth: true + + onCurrentIndexChanged: { + composerController.identitySelector.currentIndex = currentIndex + } + } + + Controls2.Button { + id: ccButton + + text: "Cc" + onClicked: { + cc.visible = true + ccButton.visible = false + } + } + + Controls2.Button { + id: bccButton + + text: "Bcc" + + onClicked: { + bcc.visible = true + bccButton.visible = false + } + } + } + } + + Controls2.TextField { + id: subject + + Layout.fillWidth: true + + placeholderText: "Enter Subject..." + + text: composerController.subject + + onTextChanged: { + composerController.subject = text; + } + } + + Controls2.TextArea { + id: content + + text: composerController.body + + onTextChanged: { + composerController.body = text; + } + + Layout.fillWidth: true + Layout.fillHeight: true + } + + RowLayout { + id: bottomBar + + width: parent.width + + Controls2.Button { + text: "Discard" + + onClicked: { + root.close() + } + } + + Item { + Layout.fillWidth: true + } + + + Controls2.Button { + text: "Save as Draft" + + enabled: saveAsDraftAction.enabled + onClicked: { + saveAsDraftAction.execute() + } + } + + Controls2.Button { + text: "Send" + + enabled: sendAction.enabled + onClicked: { + sendAction.execute() + } + } + } + } + } + } +} diff --git a/framework/qml/FolderListView.qml b/framework/qml/FolderListView.qml new file mode 100644 index 00000000..b35b52ed --- /dev/null +++ b/framework/qml/FolderListView.qml @@ -0,0 +1,195 @@ +/* + 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.4 +import QtQuick.Controls 1.4 +import QtQuick.Controls.Styles 1.4 +import QtQuick.Layouts 1.1 + +import org.kde.kirigami 1.0 as Kirigami +import org.kube.components 1.0 as KubeComponents +import org.kube.components.theme 1.0 as KubeTheme +import org.kube.framework.domain 1.0 as KubeFramework + +Rectangle { + id: root + + property variant currentFolder: null + property variant accountId + + color: KubeTheme.Colors.textColor + + KubeFramework.FolderController { + id: folderController + Binding on folder { + //!! checks for the availability of the type + when: !!root.currentFolder + value: root.currentFolder + } + } + + Menu { + id: contextMenu + title: "Edit" + + MenuItem { + text: "Synchronize" + onTriggered: { + folderController.synchronizeAction.execute() + } + } + } + + TreeView { + id: treeView + + anchors { + top: parent.top + left: parent.left + right: parent.right + } + + height: parent.height + + TableViewColumn { + title: "Name" + role: "name" + } + + model: KubeFramework.FolderListModel { + id: folderListModel + accountId: root.accountId + } + + onCurrentIndexChanged: { + model.fetchMore(currentIndex) + root.currentFolder = model.data(currentIndex, KubeFramework.FolderListModel.DomainObject) + } + + alternatingRowColors: false + headerVisible: false + + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.RightButton + onClicked: { + var index = parent.indexAt(mouse.x, mouse.y) + if (index.valid) { + folderController.folder = treeView.model.data(index, KubeFramework.FolderListModel.DomainObject) + contextMenu.popup() + } + } + } + + style: TreeViewStyle { + + rowDelegate: Rectangle { + color: styleData.selected ? KubeTheme.Colors.highlightColor : KubeTheme.Colors.textColor + + height: Kirigami.Units.gridUnit * 1.5 + width: 20 + + } + + frame: Rectangle { + color: KubeTheme.Colors.textColor + } + + branchDelegate: Item { + + width: 16; height: 16 + + Text { + + anchors.centerIn: parent + + color: KubeTheme.Colors.viewBackgroundColor + text: styleData.isExpanded ? "-" : "+" + } + + //radius: styleData.isExpanded ? 0 : 100 + } + + itemDelegate: Rectangle { + + color: styleData.selected ? KubeTheme.Colors.highlightColor : KubeTheme.Colors.textColor + + DropArea { + anchors.fill: parent + + Rectangle { + anchors.fill: parent + color: KubeTheme.Colors.viewBackgroundColor + + opacity: 0.3 + + visible: parent.containsDrag + } + onDropped: { + folderController.folder = model.domainObject + folderController.mail = drop.source.mail + folderController.moveToFolderAction.execute() + drop.accept(Qt.MoveAction) + drop.source.visible = false + } + } + + Row { + anchors { + verticalCenter: parent.verticalCenter + left: parent.left + } + Text { + anchors { + verticalCenter: parent.verticalCenter + leftMargin: Kirigami.Units.smallSpacing + } + + text: styleData.value + + color: KubeTheme.Colors.viewBackgroundColor + } + KubeComponents.Icon { + id: statusIcon + visible: false + iconName: "" + states: [ + State { + name: "busy"; when: model.status == KubeFramework.FolderListModel.InProgressStatus + PropertyChanges { target: statusIcon; iconName: KubeTheme.Icons.busy ; visible: styleData.selected } + }, + State { + name: "error"; when: model.status == KubeFramework.FolderListModel.ErrorStatus + //The error status should only be visible for a moment, otherwise we'll eventually always show errors everywhere. + PropertyChanges { target: statusIcon; iconName: KubeTheme.Icons.error; visible: styleData.selected } + }, + State { + name: "checkmark"; when: model.status == KubeFramework.FolderListModel.SuccessStatus + //The success status should only be visible for a moment, otherwise we'll eventually always show checkmarks everywhere. + PropertyChanges { target: statusIcon; iconName: KubeTheme.Icons.success; visible: styleData.selected } + } + ] + } + } + } + + backgroundColor: KubeTheme.Colors.textColor + highlightedTextColor: KubeTheme.Colors.highlightedTextColor + } + } +} diff --git a/framework/qml/Icon.qml b/framework/qml/Icon.qml new file mode 100644 index 00000000..74a4971a --- /dev/null +++ b/framework/qml/Icon.qml @@ -0,0 +1,48 @@ +/* + * 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.7 + +Item { + id: root + property string iconName + property url iconSource + property alias implicitHeight: image.implicitHeight + property alias implicitWidth: image.implicitWidth + property alias status: image.status + width: implicitWidth + height: implicitHeight + + onIconNameChanged: setImageSource() + + function setImageSource() { + if (root.iconName != "") + image.source = "image://kube/" + root.iconName; + else + image.source = ""; + } + + Image { + id: image + anchors.fill: parent + sourceSize.width: width + sourceSize.height: height + cache: true + smooth: true + } +} diff --git a/framework/qml/ListItem.qml b/framework/qml/ListItem.qml new file mode 100644 index 00000000..165ac3ab --- /dev/null +++ b/framework/qml/ListItem.qml @@ -0,0 +1,64 @@ +/* + 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.4 + +Item { + id: delegateRoot + + readonly property bool isCurrentItem: ListView.isCurrentItem + + height: Unit.width * 25 + width: parent.width + + MouseArea { + id: mouseArea + + anchors.fill: parent + } + + Rectangle { + anchors.fill: parent + + color: colorPalette.background + + //clickColor + Rectangle { + id: clickColor + + anchors.fill: parent + + color: colorPalette.selected + opacity: 0.4 + + visible: mouseArea.pressed + } + + //border + Rectangle { + + anchors.bottom: parent.bottom + + height: 1 + width: parent.width + + color: colorPalette.border + opacity: 0.2 + } + } +} diff --git a/framework/qml/MailListView.qml b/framework/qml/MailListView.qml new file mode 100644 index 00000000..2d5d6601 --- /dev/null +++ b/framework/qml/MailListView.qml @@ -0,0 +1,292 @@ +/* + 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.components.theme 1.0 as KubeTheme +import org.kube.framework.domain 1.0 as KubeFramework + +Item { + id: root + property variant parentFolder + property variant currentMail: null + property bool isDraft : false + property int currentIndex + property string filterString: searchBar.text; + + onParentFolderChanged: { + currentMail = null + } + + ToolBar { + id: toolbar + + width: parent.width + + Row { + anchors.centerIn: parent + + spacing: KubeTheme.Units.smallSpacing + + Controls.ToolButton { + iconName: KubeTheme.Icons.markAsRead + text: qsTr("Mark As Read") + enabled: mailController.markAsReadAction.enabled + tooltip: qsTr("mark mail as read") + onClicked: { + mailController.markAsReadAction.execute() + } + } + + Controls.ToolButton { + iconName: KubeTheme.Icons.markImportant + text: qsTr("Mark Important") + enabled: mailController.markAsImportantAction.enabled + tooltip: qsTr("mark mail as important") + onClicked: { + mailController.markAsImportantAction.execute() + } + } + + Controls.ToolButton { + iconName: KubeTheme.Icons.moveToTrash + text: qsTr("Delete Mail") + enabled: mailController.moveToTrashAction.enabled + tooltip: qsTr("delete email") + onClicked: { + mailController.moveToTrashAction.execute() + } + } + + Controls.ToolButton { + iconName: KubeTheme.Icons.undo + text: qsTr("Restore Mail") + enabled: mailController.restoreFromTrashAction.enabled + tooltip: qsTr("restore email") + onClicked: { + mailController.restoreFromTrashAction.execute() + } + } + } + } + + TextField { + id: searchBar + anchors.top: toolbar.bottom + width: parent.width + placeholderText: qsTr("Filter...") + } + + Label { + anchors.top: searchBar.bottom + visible: listView.count === 0 + //TODO depending on whether we synchronized already or not the label should change. + text: "Nothing here..." + } + + ListView { + id: listView + + anchors.top: searchBar.bottom + + width: parent.width + height: parent.height - toolbar.height + + focus: true + clip: true + + ScrollBar.vertical: ScrollBar{ + id: scrollbar + } + + //BEGIN keyboard nav + Keys.onDownPressed: { + incrementCurrentIndex() + } + Keys.onUpPressed: { + decrementCurrentIndex() + } + //END keyboard nav + + currentIndex: root.currentIndex + onCurrentItemChanged: { + root.currentMail = currentItem.currentData.domainObject; + root.isDraft = currentItem.currentData.draft; + } + + model: KubeFramework.MailListModel { + parentFolder: root.parentFolder + filter: root.filterString + } + + delegate: Item { + id: origin + + property variant currentData: model + + width: delegateRoot.width + height: delegateRoot.height + + Item { + id: delegateRoot + + property variant mail : model.domainObject + + width: scrollbar.visible ? listView.width - scrollbar.width : listView.width + height: KubeTheme.Units.gridUnit * 5 + + 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: background; color: KubeTheme.Colors.highlightColor} + PropertyChanges {target: subject; color: KubeTheme.Colors.highlightedTextColor} + PropertyChanges {target: sender; color: KubeTheme.Colors.highlightedTextColor} + PropertyChanges {target: date; color: KubeTheme.Colors.highlightedTextColor} + PropertyChanges {target: threadCounter; color: KubeTheme.Colors.highlightedTextColor} + }, + State { + name: "selected" + when: listView.currentIndex == index && !mouseArea.drag.active + + PropertyChanges {target: background; color: KubeTheme.Colors.highlightColor} + PropertyChanges {target: subject; color: KubeTheme.Colors.highlightedTextColor} + PropertyChanges {target: sender; color: KubeTheme.Colors.highlightedTextColor} + PropertyChanges {target: date; color: KubeTheme.Colors.highlightedTextColor} + PropertyChanges {target: threadCounter; color: KubeTheme.Colors.highlightedTextColor} + }, + State { + name: "hovered" + when: mouseArea.containsMouse && !mouseArea.drag.active + + PropertyChanges {target: background; color: KubeTheme.Colors.highlightColor; opacity: 0.7} + PropertyChanges {target: subject; color: KubeTheme.Colors.highlightedTextColor} + PropertyChanges {target: sender; color: KubeTheme.Colors.highlightedTextColor} + PropertyChanges {target: date; color: KubeTheme.Colors.highlightedTextColor} + PropertyChanges {target: threadCounter; color: KubeTheme.Colors.highlightedTextColor} + } + ] + + Drag.active: mouseArea.drag.active + Drag.hotSpot.x: mouseArea.mouseX + Drag.hotSpot.y: mouseArea.mouseY + Drag.source: delegateRoot + + MouseArea { + id: mouseArea + + anchors.fill: parent + + hoverEnabled: true + drag.target: parent + + onClicked: { + listView.currentIndex = index + } + onReleased: parent.Drag.drop() + } + + Rectangle { + id: background + + anchors.fill: parent + + color: KubeTheme.Colors.viewBackgroundColor + + border.color: KubeTheme.Colors.backgroundColor + border.width: 1 + } + + Item { + id: content + + anchors { + top: parent.top + bottom: parent.bottom + left: parent.left + right: parent.right + margins: KubeTheme.Units.smallSpacing + } + + Column { + anchors { + verticalCenter: parent.verticalCenter + left: parent.left + leftMargin: KubeTheme.Units.largeSpacing + } + + Text{ + id: subject + + text: model.subject + color: model.unread ? KubeTheme.Colors.highlightColor : KubeTheme.Colors.textColor + + maximumLineCount: 2 + width: content.width - KubeTheme.Units.gridUnit * 3 + wrapMode: Text.WrapAnywhere + elide: Text.ElideRight + } + + Text { + id: sender + + text: model.senderName + font.italic: true + color: KubeTheme.Colors.textColor + width: delegateRoot.width - KubeTheme.Units.gridUnit * 3 + elide: Text.ElideRight + } + } + + Text { + id: date + + anchors { + right: parent.right + bottom: parent.bottom + } + text: Qt.formatDateTime(model.date, "dd MMM yyyy") + font.italic: true + color: KubeTheme.Colors.disabledTextColor + font.pointSize: 9 + } + + Text { + id: threadCounter + + anchors { + right: parent.right + } + text: model.threadSize + color: model.unread ? KubeTheme.Colors.highlightColor : KubeTheme.Colors.disabledTextColor + visible: model.threadSize > 1 + } + } + } + } + } +} diff --git a/framework/qml/MailViewer.qml b/framework/qml/MailViewer.qml new file mode 100644 index 00000000..4ee170bd --- /dev/null +++ b/framework/qml/MailViewer.qml @@ -0,0 +1,76 @@ +/* + * 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.4 +import QtQuick.Controls 1.4 as Controls1 +import QtQuick.Layouts 1.1 + +import org.kube.framework.domain 1.0 as KubeFramework +import org.kube.components.mailviewer 1.0 as MV + +Item { + id: root + property variant message; + property string html; + property int desiredHeight: mailViewer.height + 20 + property variant attachments + + clip: true + + MV.MailViewer { + id: mailViewer + debug: false + width: parent.width + } + + Controls1.TreeView { + id: mailStructure + anchors.top: messageParser.attachments.rowCount() > 0 ? attachments.bottom : mailViewer.bottom + visible: mailViewer.debug + width: parent.width + height: 400 + Controls1.TableViewColumn { + role: "type" + title: "Type" + width: 300 + } + Controls1.TableViewColumn { + role: "embeded" + title: "Embeded" + width: 60 + } + Controls1.TableViewColumn { + role: "securityLevel" + title: "SecurityLevel" + width: 60 + } + Controls1.TableViewColumn { + role: "content" + title: "Content" + width: 200 + } + model: messageParser.newTree + } + + KubeFramework.MessageParser { + id: messageParser + message: root.message + } + attachments: messageParser.attachments + html: messageParser.html +} diff --git a/framework/qml/Notification.qml b/framework/qml/Notification.qml new file mode 100644 index 00000000..15291c43 --- /dev/null +++ b/framework/qml/Notification.qml @@ -0,0 +1,83 @@ +import QtQuick 2.0 +import QtQuick.Controls 2.0 + +import org.kde.kirigami 1.0 as Kirigami +import org.kube.components.theme 1.0 as KubeTheme + + +MouseArea { + id: popup + + property alias title: message.text + property alias timeout: hideTimer.interval + property alias background: bg.color + + function hide() { + if (hideTimer.running) + hideTimer.stop() + popup.opacity = 0.0 + } + + function show() { + console.warn("Trying to show the notification", title); + popup.opacity = 1.0 + hideTimer.restart() + } + + function notify(text) { + popup.title = text + bg.color = KubeTheme.Colors.textColor + show() + } + + Timer { + id: hideTimer + triggeredOnStart: false + repeat: false + interval: 5000 + onTriggered: popup.hide() + } + + width: Math.max(300, message.contentWidth + (Kirigami.Units.largeSpacing * 2)) + height: Math.max(50, message.contentHeight + (Kirigami.Units.largeSpacing * 2)) + + visible: opacity > 0 + opacity: 0.0 + + Behavior on opacity { + NumberAnimation { + duration: 200 + easing.type: Easing.InOutQuad + property: "opacity" + } + } + + Rectangle { + id: bg + + anchors.fill: parent + + opacity: 0.6 + } + + Label { + id: message + + anchors { + verticalCenter: popup.verticalCenter + left: parent.left + leftMargin: Kirigami.Units.largeSpacing + right: parent.right + rightMargin: Kirigami.Units.largeSpacing + } + + font.pixelSize: 16 + + color: KubeTheme.Colors.highlightedTextColor + horizontalAlignment: Text.AlignHCenter + elide: Text.ElideRight + wrapMode: Text.Wrap + } + + onClicked: hide() +} diff --git a/framework/qml/Outbox.qml b/framework/qml/Outbox.qml new file mode 100644 index 00000000..19646459 --- /dev/null +++ b/framework/qml/Outbox.qml @@ -0,0 +1,151 @@ +/* + 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.4 +import QtQuick.Layouts 1.1 +import QtQuick.Controls 2.0 +import QtQuick.Controls 1.3 as Controls + +import org.kde.kirigami 1.0 as Kirigami + +import org.kube.framework.actions 1.0 as KubeAction +import org.kube.framework.domain 1.0 as KubeFramework +import org.kube.components 1.0 as KubeComponents +import org.kube.components.theme 1.0 as KubeTheme + +KubeComponents.Button { + id: root + + text: outboxModel.count > 0 ? "Outbox (" + outboxModel.count + ")" : "Outbox" + color: "transparent" + textColor: KubeTheme.Colors.highlightedTextColor + iconName: "" + states: [ + State { + name: "busy"; when: outboxModel.status == KubeFramework.OutboxModel.InProgressStatus + PropertyChanges { target: root; iconName: KubeTheme.Icons.busy } + }, + State { + name: "error"; when: outboxModel.status == KubeFramework.OutboxModel.ErrorStatus + PropertyChanges { target: root; iconName: KubeTheme.Icons.error } + } + ] + + onClicked: { + dialog.visible = dialog.visible ? false : true + } + + KubeFramework.OutboxController { + id: outboxController + } + + KubeFramework.OutboxModel { + id: outboxModel + } + + Popup { + id: dialog + + height: content.height + Kirigami.Units.smallSpacing * 2 + width: content.width + Kirigami.Units.smallSpacing * 2 + + y: - dialog.height + root.height + x: root.width + + modal: true + + Item { + id: content + + anchors.centerIn: parent + + width: Kirigami.Units.gridUnit * 17 + height: listView.count * Kirigami.Units.gridUnit * 3 + sendNowButton.height + Kirigami.Units.smallSpacing + + ListView { + id: listView + + width: parent.width + height: count * Kirigami.Units.gridUnit * 3 + + model: outboxModel + + delegate: Rectangle { + id: delegateRoot + + height: Kirigami.Units.gridUnit * 3 + width: listView.width + + color: KubeTheme.Colors.viewBackgroundColor + border.color: KubeTheme.Colors.backgroundColor + border.width: 1 + + Label { + id: subjectLabel + anchors { + verticalCenter: parent.verticalCenter + left: parent.left + leftMargin: Kirigami.Units.largeSpacing + } + text: model.subject + + color: KubeTheme.Colors.textColor + opacity: 1 + states: [ + State { + name: "inprogress"; when: model.status == KubeFramework.OutboxModel.InProgressStatus + PropertyChanges { target: subjectLabel; text: "Sending: " + model.subject } + }, + State { + name: "error"; when: model.status == KubeFramework.OutboxModel.ErrorStatus + PropertyChanges { target: subjectLabel; color: KubeTheme.Colors.warningColor } + } + ] + } + } + + clip: true + } + + Button { + id: sendNowButton + + anchors { + top: listView.bottom + topMargin: Kirigami.Units.smallSpacing + horizontalCenter: parent.horizontalCenter + } + + visible: listView.count != 0 + + text: qsTr("Send now") + onClicked: { + outboxController.sendOutboxAction.execute() + } + } + + Label { + anchors.centerIn: parent + + visible: listView.count == 0 + + text: qsTr("No pending messages") + } + } + } +} diff --git a/framework/qml/OverlayDialog.qml b/framework/qml/OverlayDialog.qml new file mode 100644 index 00000000..760fb12e --- /dev/null +++ b/framework/qml/OverlayDialog.qml @@ -0,0 +1,64 @@ +/* + 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.4 +import QtQuick.Controls 1.4 +import QtQuick.Layouts 1.1 + +import org.kde.kirigami 1.0 as Kirigami + +import org.kube.framework.settings 1.0 as KubeSettings +import org.kube.framework.domain 1.0 as KubeFramework +import org.kube.components.theme 1.0 as KubeTheme + +Item { + id: root + + function closeDialog() { + root.destroy(); + } + + Rectangle { + id: background + anchors.fill: parent + + color: "black" + opacity: 0.6 + } + + MouseArea { + anchors.fill: parent + onClicked: { + root.closeDialog() + } + } + + Rectangle { + id: dialog + anchors.centerIn: parent + + height: root.height * 0.8 + width: root.width * 0.8 + + color: KubeTheme.Colors.backgroundColor + + MouseArea { + anchors.fill: parent + } + } +} diff --git a/framework/qml/People.qml b/framework/qml/People.qml new file mode 100644 index 00000000..182cce94 --- /dev/null +++ b/framework/qml/People.qml @@ -0,0 +1,435 @@ + /* + 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.7 +import QtQuick.Controls 2.0 +import QtQuick.Controls 1.4 as Controls +import QtQuick.Layouts 1.1 + +import org.kde.kirigami 1.0 as Kirigami +import org.kube.components.theme 1.0 as KubeTheme +import org.kube.framework.domain 1.0 as KubeFramework + + + +Popup { + id: popup + + property var currentContact + + modal: true + + Item { + id: peopleRoot + + anchors.fill: parent + + ToolBar { + id: toolbar + + width: parent.width + + Controls.ToolButton { + + anchors.verticalCenter: parent.verticalCenter + + iconName: KubeTheme.Icons.goBack + + onClicked: stack.pop() + + visible: stack. depth > 1 + } + + TextField { + id: searchBar + anchors.centerIn: parent + + placeholderText: "Search..." + + width: parent.width * 0.5 + } + + Controls.ToolButton { + + anchors { + right: parent.right + rightMargin: KubeTheme.Units.smallSpacing + verticalCenter: parent.verticalCenter + } + + iconName: KubeTheme.Icons.addNew + } + } + + StackView { + id: stack + + anchors { + top: toolbar.bottom + left: parent.left + right: parent.right + bottom: parent.bottom + } + + initialItem: peoplePage + + clip: true + } + } + + Component { + id: peoplePage + + Rectangle { + id: peoplePageRoot + color: KubeTheme.Colors.viewBackgroundColor + + Flickable { + + anchors.fill: parent + + ScrollBar.vertical: ScrollBar { } + contentHeight: content.height + clip: true + + Item { + id: content + + height: childrenRect.height + + Flow { + + anchors { + top: parent.top + topMargin: KubeTheme.Units.largeSpacing + left: parent.left + leftMargin: KubeTheme.Units.largeSpacing + } + + spacing: KubeTheme.Units.largeSpacing + width: peoplePageRoot.width - KubeTheme.Units.largeSpacing * 2 + + Repeater { + + model: KubeFramework.PeopleModel { + filter: searchBar.text + } + + delegate: Rectangle { + id: delegateRoot + + height: KubeTheme.Units.gridUnit * 3 + width: KubeTheme.Units.gridUnit * 10 + + border.width: 1 + border.color: "lightgrey" + + MouseArea { + anchors.fill: parent + + onClicked: { + popup.currentContact = model.domainObject + stack.push(personPage) + } + } + + Rectangle { + id: avatarPlaceholder + + height: parent.height + width: height + + color: "lightgrey" + } + + Column { + + width: parent.width + + anchors { + left: avatarPlaceholder.right + margins: KubeTheme.Units.smallSpacing + verticalCenter: parent.verticalCenter + } + + Text { + width: delegateRoot.width - avatarPlaceholder.width - KubeTheme.Units.smallSpacing * 2 + + text: model.firstName + elide: Text.ElideRight + color: KubeTheme.Colors.textColor + } + + Text { + width: delegateRoot.width - avatarPlaceholder.width - KubeTheme.Units.smallSpacing * 2 + + text: model.lastName + elide: Text.ElideRight + color: KubeTheme.Colors.textColor + } + } + } + } + } + } + } + } + } + + Component { + id: personPage + + Rectangle { + id: personPageRoot + + KubeFramework.ContactController { + id: contactController + contact: popup.currentContact + } + + color: KubeTheme.Colors.viewBackgroundColor + + Item { + + anchors { + top: parent.top + left: parent.left + leftMargin: KubeTheme.Units.largeSpacing + } + + width: parent.width + height: parent.height + + + Flickable { + + anchors.fill: parent + + ScrollBar.vertical: ScrollBar { } + contentHeight: contentColumn.height + + clip: true + + ColumnLayout { + id: contentColumn + + width: personPageRoot.width + + spacing: KubeTheme.Units.largeSpacing + + Item { + width: parent.width + height: KubeTheme.Units.smallSpacing + } + + Item { + + height: KubeTheme.Units.gridUnit * 8 + width: personPageRoot.width - KubeTheme.Units.largeSpacing + + Rectangle { + id: avatar + + height: parent.height + width: height + + color: "lightgrey" + } + + Kirigami.Heading { + id: nameLabel + + anchors { + top: avatar.top + left: avatar.right + leftMargin: KubeTheme.Units.largeSpacing + } + + text: contactController.name //"Michael Tester" + } + + Text { + id: jobTitle + + anchors { + top: nameLabel.bottom + left: avatar.right + leftMargin: KubeTheme.Units.largeSpacing + } + + text: "CIO" + } + + Rectangle { + id: company + + anchors { + bottom: avatar.bottom + left: avatar.right + leftMargin: KubeTheme.Units.largeSpacing + } + + height: KubeTheme.Units.gridUnit * 3 + width: KubeTheme.Units.gridUnit * 10 + + border.width: 1 + border.color: "lightgrey" + + Rectangle { + id: av + + height: parent.height + width: height + + color: "lightgrey" + } + + Text { + anchors { + verticalCenter: av.verticalCenter + left: av.right + leftMargin: KubeTheme.Units.smallSpacing + } + + text: "Sauerkraut AG" + + color: KubeTheme.Colors.textColor + } + } + } + + Flow { + id: emails + + width: personPageRoot.width - KubeTheme.Units.largeSpacing + + Repeater { + + model: contactController.emails + + Row { + spacing: KubeTheme.Units.smallSpacing + Text { text: "(main)" } + Text { text: modelData ; color: KubeTheme.Colors.highlightColor } + Item { width: KubeTheme.Units.smallSpacing; height: 1 } + } + } + + Row { + spacing: KubeTheme.Units.smallSpacing + Text { text: "(alias)"} + Text { text: "test.testerson@gmail.com"; color: KubeTheme.Colors.highlightColor } + Item { width: KubeTheme.Units.smallSpacing; height: 1 } + } + + Row { + spacing: KubeTheme.Units.smallSpacing + Text { text: "(private)"} + Text { text: "test@gmail.com"; color: KubeTheme.Colors.highlightColor } + Item { width: KubeTheme.Units.smallSpacing; height: 1 } + } + } + + Flow { + id: phone + + width: personPageRoot.width - KubeTheme.Units.largeSpacing + spacing: KubeTheme.Units.smallSpacing + + Row { + spacing: KubeTheme.Units.smallSpacing + Text { text: "(inhouse)"} + Text { text: "+49812324932"; opacity: 0.6 } + Item { width: KubeTheme.Units.smallSpacing; height: 1 } + } + Row { + spacing: KubeTheme.Units.smallSpacing + Text { text: "(mobile)"} + Text { text: "+49812324932"; opacity: 0.6 } + Item { width: KubeTheme.Units.smallSpacing; height: 1 } + } + Row { + spacing: KubeTheme.Units.smallSpacing + Text { text: "(private)"} + Text { text: "+49812324932"; opacity: 0.6 } + Item { width: KubeTheme.Units.smallSpacing; height: 1 } + } + } + + Column { + id: address + + width: personPageRoot.width - KubeTheme.Units.largeSpacing + + Text { text: "Albertstrasse 35a"} + Text { text: "81767 Teststadt"} + Text { text: "GERMANY" } + } + +// Column { +// +// width: parent.width +// +// spacing: KubeTheme.Units.smallSpacing +// +// Text { +// +// text: root.firstname + " is part of these groups:" +// } +// +// GroupGrid { +// id: groups +// +// width: root.width - KubeTheme.Units.largeSpacing +// +// model: GroupModel1 {} +// } +// } + +// Column { +// +// width: parent.width +// +// spacing: KubeTheme.Units.smallSpacing +// +// Text { +// id: commonPeopleLabel +// +// text: root.firstname + " is associated with:" +// } +// +// PeopleGrid { +// id: commonPeople +// +// width: root.width - KubeTheme.Units.largeSpacing +// +// model: PeopleModel2 {} +// } +// } + + Item { + width: parent.width + height: KubeTheme.Units.largeSpacing + } + } + } + } + } + } +} diff --git a/framework/qml/PositiveButton.qml b/framework/qml/PositiveButton.qml new file mode 100644 index 00000000..83063668 --- /dev/null +++ b/framework/qml/PositiveButton.qml @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2017 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.1 as Controls +import org.kube.components.theme 1.0 as KubeTheme + +Controls.AbstractButton { + id: root + + width: mainText.implicitWidth + KubeTheme.Units.largeSpacing * 2 + height: mainText.implicitHeight + KubeTheme.Units.smallSpacing * 2 + + clip: true + + Rectangle { + id: background + + anchors.fill: parent + + color: KubeTheme.Colors.positveColor + } + + Text { + id: mainText + + anchors.centerIn: parent + + color: KubeTheme.Colors.highlightedTextColor + text: root.text + } +} diff --git a/framework/qmldir b/framework/qmldir new file mode 100644 index 00000000..f258f5cc --- /dev/null +++ b/framework/qmldir @@ -0,0 +1,23 @@ +module org.kube.framework + +Avatar 1.0 Avatar.qml +FocusComposer 1.0 FocusComposer.qml +ConversationView 1.0 ConversationView.qml +FolderListView 1.0 FolderListView.qml +MailListView 1.0 MailListView.qml +AccountSwitcher 1.0 AccountSwitcher.qml +NewAccountDialog 1.0 NewAccountDialog.qml +EditAccountDialog 1.0 EditAccountDialog.qml +OverlayDialog 1.0 OverlayDialog.qml +Outbox 1.0 Outbox.qml +People 1.0 People.qml +Notification 1.0 Notification.qml +Icon 1.0 Icon.qml +Button 1.0 Button.qml +PositiveButton 1.0 PositiveButton.qml + +plugin mailplugin +plugin actionplugin +plugin notificationplugin +plugin settingsplugin +plugin accountsplugin diff --git a/framework/settings/qmldir b/framework/settings/qmldir deleted file mode 100644 index 22fec334..00000000 --- a/framework/settings/qmldir +++ /dev/null @@ -1,3 +0,0 @@ -module org.kube.framework.settings - -plugin settingsplugin -- cgit v1.2.3