summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Mollekopf <chrigi_1@fastmail.fm>2017-05-10 16:26:46 +0200
committerChristian Mollekopf <chrigi_1@fastmail.fm>2017-05-11 10:32:38 +0200
commit03fd92efdb0407b34beee13a0d2f4888b4397916 (patch)
treed24f57edc3489b531984c8f07e8ba2f4680a5e67
parent24cd706a39ac50c77dd9b88f50b8197bb2013173 (diff)
downloadkube-03fd92efdb0407b34beee13a0d2f4888b4397916.tar.gz
kube-03fd92efdb0407b34beee13a0d2f4888b4397916.zip
A new composer based on Kube.View
Kube.View is a sort of split-view that always only shows a fixed number of splits (and doesn't support manual resizing).
-rw-r--r--components/kube/contents/ui/ComposerView.qml347
-rw-r--r--components/kube/contents/ui/Kube.qml14
-rw-r--r--framework/qml/Icons.qml2
-rw-r--r--framework/qml/Messages.qml2
-rw-r--r--framework/qml/View.qml83
-rw-r--r--framework/qmldir2
-rw-r--r--framework/src/domain/maillistmodel.cpp32
-rw-r--r--framework/src/domain/maillistmodel.h4
8 files changed, 472 insertions, 14 deletions
diff --git a/components/kube/contents/ui/ComposerView.qml b/components/kube/contents/ui/ComposerView.qml
index d1bc2ea5..f6bd8396 100644
--- a/components/kube/contents/ui/ComposerView.qml
+++ b/components/kube/contents/ui/ComposerView.qml
@@ -19,20 +19,347 @@
19 19
20 20
21import QtQuick 2.7 21import QtQuick 2.7
22import QtQuick.Controls 1.3
23import QtQuick.Controls 2.0 as Controls2
24import QtQuick.Layouts 1.1
25
22import org.kube.framework 1.0 as Kube 26import org.kube.framework 1.0 as Kube
23 27
24Item { 28Kube.View {
25 id:root 29 id: root
26 signal done 30
27 property alias message: composer.message 31 property bool loadAsDraft: false
28 property alias loadAsDraft: composer.loadAsDraft 32 property variant message: {}
33
34 //FIXME mean hack to unfuck hiding
35 property variant _composerController: Kube.ComposerController {
36 id: composerController
37 onDone: Kube.Fabric.postMessage(Kube.Messages.componentDone, {})
38 }
39
40 //actions
41 property variant sendAction: composerController.sendAction
42 property variant saveAsDraftAction: composerController.saveAsDraftAction
43
44 Component.onCompleted: loadMessage(root.message, root.loadAsDraft)
45
46 function loadMessage(message, loadAsDraft) {
47 if (message) {
48 composerController.loadMessage(message, loadAsDraft)
49 }
50 }
51
52 function closeFirstSplitIfNecessary() {
53 //Move the view forward
54 if (root.currentIndex == 0) {
55 root.incrementCurrentIndex()
56 }
57 }
58
59 //Drafts
60 Rectangle {
61 width: Kube.Units.gridUnit * 20
62 Layout.minimumWidth: Kube.Units.gridUnit * 5
63 anchors {
64 top: parent.top
65 bottom: parent.bottom
66 }
67
68 color: Kube.Colors.textColor
69 focus: true
70
71 ColumnLayout {
72 anchors {
73 fill: parent
74 margins: Kube.Units.largeSpacing
75 }
76 spacing: Kube.Units.smallSpacing
77
78 Kube.PositiveButton {
79 anchors {
80 left: parent.left
81 right: parent.right
82 margins: Kube.Units.largeSpacing
83 }
84 focus: true
85 text: qsTr("New Mail")
86 onClicked: {
87 composerController.clear()
88 subject.forceActiveFocus()
89 }
90 }
91 Kube.Label{
92 text: qsTr("Drafts")
93 color: Kube.Colors.highlightedTextColor
94 }
95 ListView {
96 id: listView
97 Layout.fillHeight: true
98 anchors {
99 left: parent.left
100 right: parent.right
101 }
102
103 clip: true
104
105 // Controls2.ScrollBar.vertical: Controls2.ScrollBar {
106 // id: scrollbar
107 // }
108
109 //BEGIN keyboard nav
110 onActiveFocusChanged: {
111 if (activeFocus && currentIndex < 0) {
112 currentIndex = 0
113 }
114 }
115
116 Keys.onDownPressed: {
117 listView.incrementCurrentIndex()
118 }
119 Keys.onUpPressed: {
120 listView.decrementCurrentIndex()
121 }
122 //END keyboard nav
123
124 onCurrentItemChanged: {
125 root.loadMessage(currentItem.currentData.domainObject, true)
126 }
127
128 model: Kube.MailListModel {
129 id: mailListModel
130 showDrafts: true
131 }
132
133 delegate: Item {
134 property variant currentData: model
135
136 width: delegateRoot.width
137 height: delegateRoot.height
138
139 Item {
140 id: delegateRoot
141
142 property variant mail : model.domainObject
143
144 // width: scrollbar.visible ? listView.width - scrollbar.width : listView.width
145 width: listView.width
146 height: Kube.Units.gridUnit * 4
147
148 states: [
149 State {
150 name: "selected"
151 when: listView.currentIndex == index
152
153 PropertyChanges {target: background; color: Kube.Colors.highlightColor}
154 PropertyChanges {target: subject; color: Kube.Colors.highlightedTextColor}
155 },
156 State {
157 name: "hovered"
158 when: ( mouseArea.containsMouse || buttons.containsMouse )
159
160 PropertyChanges {target: background; color: Kube.Colors.highlightColor; opacity: 0.6}
161 PropertyChanges {target: subject; color: Kube.Colors.highlightedTextColor}
162 }
163 ]
29 164
30 Kube.FocusComposer { 165 MouseArea {
31 id: composer 166 id: mouseArea
167 anchors.fill: parent
168 hoverEnabled: true
169 onClicked: listView.currentIndex = index
170 }
171
172 Rectangle {
173 id: background
174 anchors.fill: parent
175 color: Kube.Colors.textColor
176 }
177
178 Item {
179 id: content
180
181 anchors {
182 top: parent.top
183 bottom: parent.bottom
184 left: parent.left
185 right: parent.right
186 margins: Kube.Units.smallSpacing
187 }
188
189 Column {
190 anchors {
191 verticalCenter: parent.verticalCenter
192 left: parent.left
193 leftMargin: Kube.Units.largeSpacing
194 }
195
196 Kube.Label{
197 id: subject
198 width: content.width - Kube.Units.gridUnit * 3
199 text: model.subject
200 color: Kube.Colors.highlightedTextColor
201 maximumLineCount: 2
202 wrapMode: Text.WrapAnywhere
203 elide: Text.ElideRight
204 }
205 }
206
207 Kube.Label {
208 id: date
209
210 anchors {
211 right: parent.right
212 bottom: parent.bottom
213 }
214 text: Qt.formatDateTime(model.date, "dd MMM yyyy")
215 font.italic: true
216 color: Kube.Colors.disabledTextColor
217 font.pointSize: 9
218 }
219 }
220 }
221 }
222 }
223 }
224 }
225
226 //Content
227 Rectangle {
228 Layout.fillWidth: true
229 Layout.minimumWidth: Kube.Units.gridUnit * 5
230 anchors {
231 top: parent.top
232 bottom: parent.bottom
233 }
234 color: Kube.Colors.backgroundColor
235
236 ColumnLayout {
237 anchors {
238 fill: parent
239 margins: Kube.Units.largeSpacing
240 leftMargin: Kube.Units.largeSpacing + Kube.Units.gridUnit * 2
241 rightMargin: Kube.Units.largeSpacing + Kube.Units.gridUnit * 2
242 }
243 Kube.TextField {
244 id: subject
245 Layout.fillWidth: true
246
247 placeholderText: "Enter Subject..."
248 text: composerController.subject
249 onTextChanged: composerController.subject = text;
250 onActiveFocusChanged: closeFirstSplitIfNecessary()
251 }
252
253 Controls2.TextArea {
254 id: content
255 Layout.fillWidth: true
256 Layout.fillHeight: true
257
258 text: composerController.body
259 onTextChanged: composerController.body = text;
260 onActiveFocusChanged: closeFirstSplitIfNecessary()
261 }
262 }
263 }
264
265 //Recepients
266 Rectangle {
267 width: Kube.Units.gridUnit * 20
268 Layout.minimumWidth: Kube.Units.gridUnit * 5
32 anchors { 269 anchors {
33 fill: parent 270 top: parent.top
34 margins: Kube.Units.smallSpacing 271 bottom: parent.bottom
272 }
273 color: Kube.Colors.backgroundColor
274 ColumnLayout {
275 anchors {
276 fill: parent
277 margins: Kube.Units.largeSpacing
278 }
279 width: parent.width
280
281 Kube.Label {
282 text: "Sending Email to"
283 }
284 Kube.AutocompleteLineEdit {
285 id: to
286 Layout.fillWidth: true
287 text: composerController.to
288 onTextChanged: composerController.to = text
289 model: composerController.recipientCompleter.model
290 onSearchTermChanged: composerController.recipientCompleter.searchString = searchTerm
291 }
292
293 Kube.Label {
294 text: "Sending Copy to (CC)"
295 }
296 Kube.AutocompleteLineEdit {
297 id: cc
298 Layout.fillWidth: true
299 text: composerController.cc
300 onTextChanged: composerController.cc = text
301 model: composerController.recipientCompleter.model
302 onSearchTermChanged: composerController.recipientCompleter.searchString = searchTerm
303 }
304
305 Kube.Label {
306 text: "Sending Secret Copy to (Bcc)"
307 }
308 Kube.AutocompleteLineEdit {
309 id: bcc
310 Layout.fillWidth: true
311 text: composerController.bcc
312 onTextChanged: composerController.bcc = text;
313 model: composerController.recipientCompleter.model
314 onSearchTermChanged: composerController.recipientCompleter.searchString = searchTerm
315 }
316
317 Item {
318 Layout.fillHeight: true
319 }
320
321
322 Item {
323 Layout.fillHeight: true
324 }
325
326
327 Kube.Button {
328 id: saveDraftButton
329
330 text: "Save as Draft"
331 //TODO enabled: saveAsDraftAction.enabled
332 onClicked: {
333 saveAsDraftAction.execute()
334 }
335 }
336 Kube.Button {
337 text: "Discard"
338 onClicked: Kube.Fabric.postMessage(Kube.Messages.componentDone, {})
339 }
340
341 Kube.Label {
342 text: "You are sending this from:"
343 }
344 Kube.ComboBox {
345 id: identityCombo
346 model: composerController.identitySelector.model
347 textRole: "displayName"
348 Layout.fillWidth: true
349 onCurrentIndexChanged: {
350 composerController.identitySelector.currentIndex = currentIndex
351 }
352 }
353
354 Kube.PositiveButton {
355 width: saveDraftButton.width
356
357 text: "Send"
358 enabled: sendAction.enabled
359 onClicked: {
360 sendAction.execute()
361 }
362 }
35 } 363 }
36 onDone: root.done()
37 } 364 }
38} 365}
diff --git a/components/kube/contents/ui/Kube.qml b/components/kube/contents/ui/Kube.qml
index 115123b7..21c6f4fd 100644
--- a/components/kube/contents/ui/Kube.qml
+++ b/components/kube/contents/ui/Kube.qml
@@ -117,10 +117,12 @@ Controls2.ApplicationWindow {
117 117
118 Kube.IconButton { 118 Kube.IconButton {
119 iconName: Kube.Icons.search_inverted 119 iconName: Kube.Icons.search_inverted
120 onClicked: search.open()
121 }
120 122
121 onClicked: { 123 Kube.IconButton {
122 search.open() 124 iconName: Kube.Icons.edit_inverted
123 } 125 onClicked: kubeViews.openComposer()
124 } 126 }
125 127
126 Kube.IconButton { 128 Kube.IconButton {
@@ -166,6 +168,11 @@ Controls2.ApplicationWindow {
166 Layout.fillWidth: true 168 Layout.fillWidth: true
167 initialItem: mailView 169 initialItem: mailView
168 170
171 Kube.Listener {
172 filter: Kube.Messages.componentDone
173 onMessageReceived: kubeViews.pop({immediate: true})
174 }
175
169 function setPeopleView() { 176 function setPeopleView() {
170 //TODO replacing here while a composer is open is destructive 177 //TODO replacing here while a composer is open is destructive
171 kubeViews.push({item: peopleView, replace: true, immediate: true}) 178 kubeViews.push({item: peopleView, replace: true, immediate: true})
@@ -202,7 +209,6 @@ Controls2.ApplicationWindow {
202 Component { 209 Component {
203 id: composerView 210 id: composerView
204 ComposerView { 211 ComposerView {
205 onDone: kubeViews.pop({immediate: true})
206 } 212 }
207 } 213 }
208 Component { 214 Component {
diff --git a/framework/qml/Icons.qml b/framework/qml/Icons.qml
index add51534..05cde6c9 100644
--- a/framework/qml/Icons.qml
+++ b/framework/qml/Icons.qml
@@ -38,6 +38,7 @@ Item {
38 property string undo: "edit-undo-inverted" 38 property string undo: "edit-undo-inverted"
39 property string moveToTrash: "kubetrash" 39 property string moveToTrash: "kubetrash"
40 property string edit: "document-edit" 40 property string edit: "document-edit"
41 property string edit_inverted: "document-edit-inverted"
41 property string replyToSender: "mail-reply-sender" 42 property string replyToSender: "mail-reply-sender"
42 property string outbox: "mail-folder-outbox" 43 property string outbox: "mail-folder-outbox"
43 property string outbox_inverted: "mail-folder-outbox-inverted" 44 property string outbox_inverted: "mail-folder-outbox-inverted"
@@ -47,6 +48,7 @@ Item {
47 property string search_inverted: "edit-find-inverted" 48 property string search_inverted: "edit-find-inverted"
48 property string mail_inverted: "mail-message-inverted" 49 property string mail_inverted: "mail-message-inverted"
49 property string goBack: "go-previous" 50 property string goBack: "go-previous"
51 property string goBack_inverted: "go-previous-inverted"
50 property string goDown: "go-down" 52 property string goDown: "go-down"
51 property string goUp: "go-down" 53 property string goUp: "go-down"
52 54
diff --git a/framework/qml/Messages.qml b/framework/qml/Messages.qml
index 19d0c402..aa43de76 100644
--- a/framework/qml/Messages.qml
+++ b/framework/qml/Messages.qml
@@ -41,5 +41,7 @@ Item {
41 property string reply: "reply" 41 property string reply: "reply"
42 property string edit: "edit" 42 property string edit: "edit"
43 property string compose: "compose" 43 property string compose: "compose"
44
45 property string componentDone: "done"
44} 46}
45 47
diff --git a/framework/qml/View.qml b/framework/qml/View.qml
new file mode 100644
index 00000000..6a0b51b4
--- /dev/null
+++ b/framework/qml/View.qml
@@ -0,0 +1,83 @@
1/*
2 * Copyright (C) 2017 Michael Bohlender, <michael.bohlender@kdemail.net>
3 * Copyright (C) 2017 Christian Mollekopf, <mollekopf@kolabsys.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20
21import QtQuick 2.7
22import QtQuick.Controls 1.3
23import QtQuick.Controls 2.0 as Controls2
24import QtQuick.Layouts 1.1
25import org.kube.framework 1.0 as Kube
26
27Item {
28 id: container
29
30 property int visibleViews: 2
31 property int currentIndex: 0
32 property int count: contentItems.length
33 default property alias contentItems: content.data
34
35 onCurrentIndexChanged: showRelevantSplits()
36 Component.onCompleted: showRelevantSplits()
37
38 function incrementCurrentIndex() {
39 if (currentIndex < count) {
40 currentIndex = currentIndex + 1
41 }
42 }
43
44 function decrementCurrentIndex() {
45 if (currentIndex > 0) {
46 currentIndex = currentIndex - 1
47 }
48 }
49
50 function showRelevantSplits() {
51 var i;
52 for (i = 0; i < count; i++) {
53 if (i < currentIndex) {
54 contentItems[i].visible = false;
55 } else if (i > (currentIndex + visibleViews - 1)) {
56 contentItems[i].visible = false;
57 } else {
58 contentItems[i].visible = true;
59 }
60 }
61
62 }
63
64 Kube.IconButton {
65 anchors {
66 top: container.top
67 left: container.left
68 }
69 z: 1
70 background: Rectangle {
71 anchors.fill: parent
72 color: Kube.Colors.textColor
73 }
74 iconName: Kube.Icons.goBack_inverted
75 visible: currentIndex > 0
76 onClicked: decrementCurrentIndex()
77 }
78
79 RowLayout {
80 id: content
81 anchors.fill: parent
82 }
83}
diff --git a/framework/qmldir b/framework/qmldir
index 8b0c52ac..2060a920 100644
--- a/framework/qmldir
+++ b/framework/qmldir
@@ -22,6 +22,8 @@ ComboBox 1.0 ComboBox.qml
22PositiveButton 1.0 PositiveButton.qml 22PositiveButton 1.0 PositiveButton.qml
23TextField 1.0 TextField.qml 23TextField 1.0 TextField.qml
24Label 1.0 Label.qml 24Label 1.0 Label.qml
25View 1.0 View.qml
26AutocompleteLineEdit 1.0 AutocompleteLineEdit.qml
25singleton Messages 1.0 Messages.qml 27singleton Messages 1.0 Messages.qml
26singleton Colors 1.0 Colors.qml 28singleton Colors 1.0 Colors.qml
27singleton Icons 1.0 Icons.qml 29singleton Icons 1.0 Icons.qml
diff --git a/framework/src/domain/maillistmodel.cpp b/framework/src/domain/maillistmodel.cpp
index 0f477624..73d686eb 100644
--- a/framework/src/domain/maillistmodel.cpp
+++ b/framework/src/domain/maillistmodel.cpp
@@ -302,3 +302,35 @@ QVariant MailListModel::mail() const
302} 302}
303 303
304 304
305void MailListModel::setShowDrafts(bool)
306{
307 using namespace Sink::ApplicationDomain;
308 Sink::Query query;
309 // query.setFlags(Sink::Query::LiveQuery | Sink::Query::UpdateStatus);
310 query.filter<Mail::Draft>(true);
311 query.request<Mail::Subject>();
312 query.request<Mail::Sender>();
313 query.request<Mail::To>();
314 query.request<Mail::Cc>();
315 query.request<Mail::Bcc>();
316 query.request<Mail::Date>();
317 query.request<Mail::Unread>();
318 query.request<Mail::Important>();
319 query.request<Mail::Draft>();
320 query.request<Mail::Folder>();
321 query.request<Mail::Sent>();
322 query.request<Mail::Trash>();
323 query.request<Mail::MimeMessage>();
324 query.request<Mail::FullPayloadAvailable>();
325 mFetchMails = true;
326 mFetchedMails.clear();
327 qDebug() << "Running mail query for drafts: ";
328 //Latest mail at the top
329 sort(0, Qt::AscendingOrder);
330 runQuery(query);
331}
332
333bool MailListModel::showDrafts() const
334{
335 return false;
336}
diff --git a/framework/src/domain/maillistmodel.h b/framework/src/domain/maillistmodel.h
index 5ed081f4..5f593700 100644
--- a/framework/src/domain/maillistmodel.h
+++ b/framework/src/domain/maillistmodel.h
@@ -31,6 +31,7 @@ class MailListModel : public QSortFilterProxyModel
31 Q_OBJECT 31 Q_OBJECT
32 Q_PROPERTY (QVariant parentFolder READ parentFolder WRITE setParentFolder) 32 Q_PROPERTY (QVariant parentFolder READ parentFolder WRITE setParentFolder)
33 Q_PROPERTY (QVariant mail READ mail WRITE setMail) 33 Q_PROPERTY (QVariant mail READ mail WRITE setMail)
34 Q_PROPERTY (bool showDrafts READ showDrafts WRITE setShowDrafts)
34 Q_PROPERTY (QString filter READ filter WRITE setFilter) 35 Q_PROPERTY (QString filter READ filter WRITE setFilter)
35 Q_PROPERTY (bool isThreaded READ isThreaded NOTIFY isThreadedChanged) 36 Q_PROPERTY (bool isThreaded READ isThreaded NOTIFY isThreadedChanged)
36 37
@@ -87,6 +88,9 @@ public:
87 void setFilter(const QString &mail); 88 void setFilter(const QString &mail);
88 QString filter() const; 89 QString filter() const;
89 90
91 void setShowDrafts(bool);
92 bool showDrafts() const;
93
90signals: 94signals:
91 void isThreadedChanged(); 95 void isThreadedChanged();
92 96