diff options
author | Christian Mollekopf <chrigi_1@fastmail.fm> | 2018-01-09 09:35:59 +0100 |
---|---|---|
committer | Christian Mollekopf <chrigi_1@fastmail.fm> | 2018-01-10 12:42:13 +0100 |
commit | 6d726bb10386b3d7f5481d41b735ec06cb2163ad (patch) | |
tree | 4d591b67b54c5a83f9f1d718a4576c8ccf05859b /views/composer/qml/View.qml | |
parent | 2d9944bd0b5cd1dd202d9dc6318d612e1aca4241 (diff) | |
download | kube-6d726bb10386b3d7f5481d41b735ec06cb2163ad.tar.gz kube-6d726bb10386b3d7f5481d41b735ec06cb2163ad.zip |
Install composer/converations/people as separate views and load them
dynamically.
Diffstat (limited to 'views/composer/qml/View.qml')
-rw-r--r-- | views/composer/qml/View.qml | 533 |
1 files changed, 533 insertions, 0 deletions
diff --git a/views/composer/qml/View.qml b/views/composer/qml/View.qml new file mode 100644 index 00000000..1eb88bb4 --- /dev/null +++ b/views/composer/qml/View.qml | |||
@@ -0,0 +1,533 @@ | |||
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 | |||
21 | import QtQuick 2.7 | ||
22 | import QtQuick.Controls 1.3 | ||
23 | import QtQuick.Controls 2.0 as Controls2 | ||
24 | import QtQuick.Layouts 1.1 | ||
25 | import QtQuick.Dialogs 1.0 as Dialogs | ||
26 | |||
27 | import org.kube.framework 1.0 as Kube | ||
28 | |||
29 | Kube.View { | ||
30 | id: root | ||
31 | |||
32 | property bool newMessage: false | ||
33 | property bool loadAsDraft: false | ||
34 | property variant message: {} | ||
35 | property variant recipients: [] | ||
36 | |||
37 | resources: [ | ||
38 | Kube.ComposerController { | ||
39 | id: composerController | ||
40 | htmlBody: html.checked | ||
41 | sign: signCheckbox.checked | ||
42 | encrypt: encryptCheckbox.checked | ||
43 | onDone: Kube.Fabric.postMessage(Kube.Messages.componentDone, {}) | ||
44 | |||
45 | property bool foundAllKeys: to.foundAllKeys && cc.foundAllKeys && bcc.foundAllKeys | ||
46 | |||
47 | sendAction.enabled: composerController.accountId && composerController.subject && (!composerController.encrypt || composerController.foundAllKeys) && (!composerController.sign && !composerController.encrypt || composerController.foundPersonalKeys) | ||
48 | saveAsDraftAction.enabled: composerController.accountId | ||
49 | } | ||
50 | ] | ||
51 | |||
52 | Component.onCompleted: loadMessage(root.message, root.loadAsDraft) | ||
53 | |||
54 | Controls2.StackView.onActivated: { | ||
55 | Kube.Fabric.postMessage(Kube.Messages.synchronize, {"type": "mail", "specialPurpose": "drafts"}) | ||
56 | //For autocompletion | ||
57 | Kube.Fabric.postMessage(Kube.Messages.synchronize, {"type": "contacts"}) | ||
58 | } | ||
59 | |||
60 | function loadMessage(message, loadAsDraft) { | ||
61 | if (message) { | ||
62 | composerController.loadMessage(message, loadAsDraft) | ||
63 | //Forward focus for replies directly | ||
64 | if (!loadAsDraft) { | ||
65 | subject.forceActiveFocus() | ||
66 | } | ||
67 | } else if (newMessage) { | ||
68 | composerController.clear() | ||
69 | if (root.recipients) { | ||
70 | for (var i = 0; i < root.recipients.length; ++i) { | ||
71 | composerController.to.add({name: root.recipients[i]}) | ||
72 | } | ||
73 | } | ||
74 | subject.forceActiveFocus() | ||
75 | } | ||
76 | } | ||
77 | |||
78 | function closeFirstSplitIfNecessary() { | ||
79 | //Move the view forward | ||
80 | if (root.currentIndex == 0) { | ||
81 | root.incrementCurrentIndex() | ||
82 | } | ||
83 | } | ||
84 | |||
85 | //Drafts | ||
86 | Rectangle { | ||
87 | |||
88 | anchors { | ||
89 | top: parent.top | ||
90 | bottom: parent.bottom | ||
91 | } | ||
92 | |||
93 | width: Kube.Units.gridUnit * 10 | ||
94 | Layout.minimumWidth: Kube.Units.gridUnit * 5 | ||
95 | |||
96 | color: Kube.Colors.textColor | ||
97 | |||
98 | ColumnLayout { | ||
99 | |||
100 | anchors { | ||
101 | fill: parent | ||
102 | margins: Kube.Units.largeSpacing | ||
103 | } | ||
104 | |||
105 | spacing: Kube.Units.largeSpacing | ||
106 | |||
107 | Kube.PositiveButton { | ||
108 | objectName: "newMailButton" | ||
109 | anchors { | ||
110 | left: parent.left | ||
111 | right: parent.right | ||
112 | } | ||
113 | focus: true | ||
114 | text: qsTr("New Email") | ||
115 | onClicked: { | ||
116 | listView.currentIndex = -1 | ||
117 | composerController.clear() | ||
118 | subject.forceActiveFocus() | ||
119 | } | ||
120 | } | ||
121 | |||
122 | Kube.Label{ | ||
123 | text: qsTr("Drafts") | ||
124 | color: Kube.Colors.highlightedTextColor | ||
125 | } | ||
126 | |||
127 | Kube.ListView { | ||
128 | id: listView | ||
129 | activeFocusOnTab: true | ||
130 | |||
131 | anchors { | ||
132 | left: parent.left | ||
133 | right: parent.right | ||
134 | } | ||
135 | |||
136 | Layout.fillHeight: true | ||
137 | clip: true | ||
138 | currentIndex: -1 | ||
139 | highlightFollowsCurrentItem: false | ||
140 | |||
141 | //BEGIN keyboard nav | ||
142 | onActiveFocusChanged: { | ||
143 | if (activeFocus && currentIndex < 0) { | ||
144 | currentIndex = 0 | ||
145 | } | ||
146 | } | ||
147 | Keys.onDownPressed: { | ||
148 | listView.incrementCurrentIndex() | ||
149 | } | ||
150 | Keys.onUpPressed: { | ||
151 | listView.decrementCurrentIndex() | ||
152 | } | ||
153 | //END keyboard nav | ||
154 | |||
155 | onCurrentItemChanged: { | ||
156 | if (currentItem) { | ||
157 | root.loadMessage(currentItem.currentData.domainObject, true) | ||
158 | } | ||
159 | } | ||
160 | |||
161 | model: Kube.MailListModel { | ||
162 | id: mailListModel | ||
163 | showDrafts: true | ||
164 | } | ||
165 | |||
166 | delegate: Kube.ListDelegate { | ||
167 | id: delegateRoot | ||
168 | |||
169 | color: Kube.Colors.textColor | ||
170 | border.width: 0 | ||
171 | |||
172 | Item { | ||
173 | id: content | ||
174 | |||
175 | anchors { | ||
176 | fill: parent | ||
177 | margins: Kube.Units.smallSpacing | ||
178 | } | ||
179 | |||
180 | Kube.Label { | ||
181 | width: content.width | ||
182 | text: model.subject == "" ? "no subject" : model.subject | ||
183 | color: Kube.Colors.highlightedTextColor | ||
184 | maximumLineCount: 2 | ||
185 | wrapMode: Text.WrapAnywhere | ||
186 | elide: Text.ElideRight | ||
187 | } | ||
188 | |||
189 | Kube.Label { | ||
190 | anchors { | ||
191 | right: parent.right | ||
192 | bottom: parent.bottom | ||
193 | } | ||
194 | text: Qt.formatDateTime(model.date, "dd MMM yyyy") | ||
195 | font.italic: true | ||
196 | color: Kube.Colors.disabledTextColor | ||
197 | font.pointSize: Kube.Units.smallFontSize | ||
198 | visible: !delegateRoot.hovered | ||
199 | } | ||
200 | } | ||
201 | Row { | ||
202 | id: buttons | ||
203 | |||
204 | anchors { | ||
205 | right: parent.right | ||
206 | bottom: parent.bottom | ||
207 | margins: Kube.Units.smallSpacing | ||
208 | } | ||
209 | |||
210 | visible: delegateRoot.hovered | ||
211 | spacing: Kube.Units.smallSpacing | ||
212 | opacity: 0.7 | ||
213 | |||
214 | Kube.IconButton { | ||
215 | id: deleteButton | ||
216 | activeFocusOnTab: true | ||
217 | iconName: Kube.Icons.moveToTrash | ||
218 | visible: enabled | ||
219 | enabled: !!model.mail | ||
220 | onClicked: Kube.Fabric.postMessage(Kube.Messages.moveToTrash, {"mail": model.mail}) | ||
221 | } | ||
222 | } | ||
223 | } | ||
224 | } | ||
225 | } | ||
226 | } | ||
227 | |||
228 | //Content | ||
229 | Rectangle { | ||
230 | Layout.fillWidth: true | ||
231 | Layout.minimumWidth: Kube.Units.gridUnit * 5 | ||
232 | anchors { | ||
233 | top: parent.top | ||
234 | bottom: parent.bottom | ||
235 | } | ||
236 | color: Kube.Colors.backgroundColor | ||
237 | |||
238 | ColumnLayout { | ||
239 | anchors { | ||
240 | fill: parent | ||
241 | margins: Kube.Units.largeSpacing | ||
242 | leftMargin: Kube.Units.largeSpacing + Kube.Units.gridUnit * 2 | ||
243 | rightMargin: Kube.Units.largeSpacing + Kube.Units.gridUnit * 2 | ||
244 | } | ||
245 | |||
246 | spacing: Kube.Units.smallSpacing | ||
247 | |||
248 | Kube.TextField { | ||
249 | id: subject | ||
250 | Layout.fillWidth: true | ||
251 | activeFocusOnTab: true | ||
252 | |||
253 | placeholderText: qsTr("Enter Subject...") | ||
254 | text: composerController.subject | ||
255 | onTextChanged: composerController.subject = text; | ||
256 | onActiveFocusChanged: { | ||
257 | if (activeFocus) { | ||
258 | closeFirstSplitIfNecessary() | ||
259 | } | ||
260 | } | ||
261 | } | ||
262 | |||
263 | Flow { | ||
264 | id: attachments | ||
265 | |||
266 | Layout.fillWidth: true | ||
267 | layoutDirection: Qt.RightToLeft | ||
268 | spacing: Kube.Units.smallSpacing | ||
269 | clip: true | ||
270 | |||
271 | Repeater { | ||
272 | model: composerController.attachments.model | ||
273 | delegate: Kube.AttachmentDelegate { | ||
274 | name: model.filename | ||
275 | icon: model.iconname | ||
276 | clip: true | ||
277 | actionIcon: Kube.Icons.remove | ||
278 | onExecute: composerController.attachments.remove(model.id) | ||
279 | } | ||
280 | } | ||
281 | } | ||
282 | |||
283 | RowLayout { | ||
284 | |||
285 | spacing: Kube.Units.largeSpacing | ||
286 | |||
287 | Kube.Switch { | ||
288 | id: html | ||
289 | text: checked ? qsTr("plain") : qsTr("html") | ||
290 | focusPolicy: Qt.TabFocus | ||
291 | focus: false | ||
292 | checked: composerController.htmlBody | ||
293 | } | ||
294 | |||
295 | Row { | ||
296 | visible: html.checked | ||
297 | spacing: 1 | ||
298 | |||
299 | Kube.IconButton { | ||
300 | iconName: Kube.Icons.bold | ||
301 | checkable: true | ||
302 | checked: textEditor.bold | ||
303 | onClicked: textEditor.bold = !textEditor.bold | ||
304 | focusPolicy: Qt.TabFocus | ||
305 | focus: false | ||
306 | } | ||
307 | Kube.IconButton { | ||
308 | iconName: Kube.Icons.italic | ||
309 | checkable: true | ||
310 | checked: textEditor.italic | ||
311 | onClicked: textEditor.italic = !textEditor.italic | ||
312 | focusPolicy: Qt.TabFocus | ||
313 | focus: false | ||
314 | } | ||
315 | Kube.IconButton { | ||
316 | iconName: Kube.Icons.underline | ||
317 | checkable: true | ||
318 | checked: textEditor.underline | ||
319 | onClicked: textEditor.underline = !textEditor.underline | ||
320 | focusPolicy: Qt.TabFocus | ||
321 | focus: false | ||
322 | } | ||
323 | } | ||
324 | |||
325 | Item { | ||
326 | height: 1 | ||
327 | Layout.fillWidth: true | ||
328 | } | ||
329 | |||
330 | Kube.Button { | ||
331 | text: qsTr("Attach file") | ||
332 | |||
333 | onClicked: { | ||
334 | fileDialogComponent.createObject(parent) | ||
335 | } | ||
336 | |||
337 | Component { | ||
338 | id: fileDialogComponent | ||
339 | Dialogs.FileDialog { | ||
340 | id: fileDialog | ||
341 | visible: true | ||
342 | title: "Choose a file to attach" | ||
343 | selectFolder: false | ||
344 | onAccepted: { | ||
345 | composerController.attachments.add({url: fileDialog.fileUrl}) | ||
346 | } | ||
347 | } | ||
348 | } | ||
349 | } | ||
350 | } | ||
351 | |||
352 | Kube.TextEditor { | ||
353 | id: textEditor | ||
354 | |||
355 | Layout.fillWidth: true | ||
356 | Layout.fillHeight: true | ||
357 | htmlEnabled: html.checked | ||
358 | |||
359 | onActiveFocusChanged: closeFirstSplitIfNecessary() | ||
360 | Keys.onEscapePressed: recipients.forceActiveFocus() | ||
361 | initialText: composerController.body | ||
362 | onTextChanged: composerController.body = text; | ||
363 | } | ||
364 | } | ||
365 | } | ||
366 | |||
367 | //Recepients | ||
368 | FocusScope { | ||
369 | id: recipients | ||
370 | anchors { | ||
371 | top: parent.top | ||
372 | bottom: parent.bottom | ||
373 | } | ||
374 | width: Kube.Units.gridUnit * 15 | ||
375 | activeFocusOnTab: true | ||
376 | |||
377 | //background | ||
378 | Rectangle { | ||
379 | anchors.fill: parent | ||
380 | color: Kube.Colors.backgroundColor | ||
381 | |||
382 | Rectangle { | ||
383 | height: parent.height | ||
384 | width: 1 | ||
385 | color: Kube.Colors.buttonColor | ||
386 | } | ||
387 | } | ||
388 | |||
389 | //Content | ||
390 | ColumnLayout { | ||
391 | anchors { | ||
392 | fill: parent | ||
393 | margins: Kube.Units.largeSpacing | ||
394 | } | ||
395 | |||
396 | spacing: Kube.Units.largeSpacing | ||
397 | ColumnLayout { | ||
398 | Layout.maximumWidth: parent.width | ||
399 | Layout.fillWidth: true | ||
400 | Layout.fillHeight: true | ||
401 | |||
402 | Kube.Label { | ||
403 | text: qsTr("Sending Email to:") | ||
404 | } | ||
405 | |||
406 | AddresseeListEditor { | ||
407 | Layout.preferredHeight: implicitHeight | ||
408 | Layout.fillWidth: true | ||
409 | focus: true | ||
410 | activeFocusOnTab: true | ||
411 | encrypt: composerController.encrypt | ||
412 | controller: composerController.to | ||
413 | completer: composerController.recipientCompleter | ||
414 | } | ||
415 | |||
416 | Kube.Label { | ||
417 | text: qsTr("Sending Copy to (CC):") | ||
418 | } | ||
419 | AddresseeListEditor { | ||
420 | id: cc | ||
421 | Layout.preferredHeight: cc.implicitHeight | ||
422 | Layout.fillWidth: true | ||
423 | activeFocusOnTab: true | ||
424 | encrypt: composerController.encrypt | ||
425 | controller: composerController.cc | ||
426 | completer: composerController.recipientCompleter | ||
427 | } | ||
428 | |||
429 | Kube.Label { | ||
430 | text: qsTr("Sending Secret Copy to (Bcc):") | ||
431 | } | ||
432 | AddresseeListEditor { | ||
433 | id: bcc | ||
434 | Layout.preferredHeight: bcc.implicitHeight | ||
435 | Layout.fillWidth: true | ||
436 | activeFocusOnTab: true | ||
437 | encrypt: composerController.encrypt | ||
438 | controller: composerController.bcc | ||
439 | completer: composerController.recipientCompleter | ||
440 | } | ||
441 | Item { | ||
442 | width: parent.width | ||
443 | Layout.fillHeight: true | ||
444 | } | ||
445 | } | ||
446 | |||
447 | RowLayout { | ||
448 | enabled: composerController.foundPersonalKeys | ||
449 | Kube.CheckBox { | ||
450 | id: encryptCheckbox | ||
451 | checked: composerController.encrypt | ||
452 | } | ||
453 | Kube.Label { | ||
454 | text: qsTr("encrypt") | ||
455 | } | ||
456 | } | ||
457 | |||
458 | RowLayout { | ||
459 | enabled: composerController.foundPersonalKeys | ||
460 | Kube.CheckBox { | ||
461 | id: signCheckbox | ||
462 | checked: composerController.sign | ||
463 | } | ||
464 | Kube.Label { | ||
465 | text: qsTr("sign") | ||
466 | } | ||
467 | } | ||
468 | Kube.Label { | ||
469 | visible: !composerController.foundPersonalKeys | ||
470 | Layout.maximumWidth: parent.width | ||
471 | text: qsTr("Encryption is not available because your personal key has not been found.") | ||
472 | wrapMode: Text.Wrap | ||
473 | } | ||
474 | |||
475 | RowLayout { | ||
476 | Layout.maximumWidth: parent.width | ||
477 | width: parent.width | ||
478 | height: Kube.Units.gridUnit | ||
479 | |||
480 | Kube.Button { | ||
481 | width: saveDraftButton.width | ||
482 | text: qsTr("Discard") | ||
483 | onClicked: Kube.Fabric.postMessage(Kube.Messages.componentDone, {}) | ||
484 | } | ||
485 | |||
486 | Kube.Button { | ||
487 | id: saveDraftButton | ||
488 | |||
489 | text: qsTr("Save as Draft") | ||
490 | enabled: composerController.saveAsDraftAction.enabled | ||
491 | onClicked: { | ||
492 | composerController.saveAsDraftAction.execute() | ||
493 | } | ||
494 | } | ||
495 | } | ||
496 | |||
497 | ColumnLayout { | ||
498 | Layout.maximumWidth: parent.width | ||
499 | Layout.fillWidth: true | ||
500 | Kube.Label { | ||
501 | id: fromLabel | ||
502 | text: qsTr("You are sending this from:") | ||
503 | } | ||
504 | |||
505 | Kube.ComboBox { | ||
506 | id: identityCombo | ||
507 | |||
508 | width: parent.width - Kube.Units.largeSpacing * 2 | ||
509 | |||
510 | model: composerController.identitySelector.model | ||
511 | textRole: "address" | ||
512 | Layout.fillWidth: true | ||
513 | onCurrentIndexChanged: { | ||
514 | composerController.identitySelector.currentIndex = currentIndex | ||
515 | } | ||
516 | } | ||
517 | } | ||
518 | |||
519 | Kube.PositiveButton { | ||
520 | objectName: "sendButton" | ||
521 | id: sendButton | ||
522 | |||
523 | width: parent.width | ||
524 | |||
525 | text: qsTr("Send") | ||
526 | enabled: composerController.sendAction.enabled | ||
527 | onClicked: { | ||
528 | composerController.sendAction.execute() | ||
529 | } | ||
530 | } | ||
531 | } | ||
532 | }//FocusScope | ||
533 | } | ||