summaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
authorChristian Mollekopf <chrigi_1@fastmail.fm>2018-01-09 09:35:59 +0100
committerChristian Mollekopf <chrigi_1@fastmail.fm>2018-01-10 12:42:13 +0100
commit6d726bb10386b3d7f5481d41b735ec06cb2163ad (patch)
tree4d591b67b54c5a83f9f1d718a4576c8ccf05859b /components
parent2d9944bd0b5cd1dd202d9dc6318d612e1aca4241 (diff)
downloadkube-6d726bb10386b3d7f5481d41b735ec06cb2163ad.tar.gz
kube-6d726bb10386b3d7f5481d41b735ec06cb2163ad.zip
Install composer/converations/people as separate views and load them
dynamically.
Diffstat (limited to 'components')
-rw-r--r--components/kube/qml/AccountsView.qml143
-rw-r--r--components/kube/qml/AddresseeListEditor.qml138
-rw-r--r--components/kube/qml/ComposerView.qml533
-rw-r--r--components/kube/qml/Kube.qml228
-rw-r--r--components/kube/qml/LogView.qml329
-rw-r--r--components/kube/qml/LoginView.qml52
-rw-r--r--components/kube/qml/MailView.qml120
-rw-r--r--components/kube/qml/PeopleView.qml38
-rw-r--r--components/kube/qml/ViewManager.qml84
-rw-r--r--components/kube/tests/tst_accountsview.qml37
-rw-r--r--components/kube/tests/tst_composerview.qml97
-rw-r--r--components/kube/tests/tst_logview.qml65
-rw-r--r--components/kube/tests/tst_mailview.qml37
-rw-r--r--components/kube/tests/tst_peopleview.qml37
14 files changed, 147 insertions, 1791 deletions
diff --git a/components/kube/qml/AccountsView.qml b/components/kube/qml/AccountsView.qml
deleted file mode 100644
index 9b774907..00000000
--- a/components/kube/qml/AccountsView.qml
+++ /dev/null
@@ -1,143 +0,0 @@
1/*
2 * Copyright (C) 2017 Michael Bohlender, <michael.bohlender@kdemail.net>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19import QtQuick 2.4
20import QtQuick.Layouts 1.1
21import QtQuick.Controls 1.3 as Controls
22import QtQuick.Controls 2.0
23import org.kube.framework 1.0 as Kube
24import org.kube.components.accounts 1.0 as KubeAccounts
25
26FocusScope {
27 id: root
28 //Defines whether more than one account is supported.
29 property bool singleAccountMode: false
30 //Defines available account types.
31 property var availableAccountPlugins: ["kolabnow", "imap", "maildir", "gmail"]
32
33 Controls.SplitView {
34 height: parent.height
35 width: parent.width
36
37 Item {
38 id: accountList
39 width: Kube.Units.gridUnit * 12
40 Layout.fillHeight: true
41 visible: !root.singleAccountMode
42
43 Kube.PositiveButton {
44 id: newAccountButton
45 anchors {
46 top: parent.top
47 left: parent.left
48 right: parent.right
49 margins: Kube.Units.largeSpacing
50 }
51 text: qsTr("New Account")
52
53 onClicked: accountWizard.open()
54 }
55
56 Kube.ListView {
57 id: listView
58
59 anchors {
60 top: newAccountButton.bottom
61 left: parent.left
62 right: parent.right
63 bottom: parent.bottom
64 topMargin: Kube.Units.largeSpacing
65 }
66
67 clip: true
68
69 model: Kube.AccountsModel {}
70
71 onCurrentItemChanged: {
72 if (currentItem) {
73 edit.accountId = currentItem.currentData.accountId
74 }
75 }
76
77 delegate: Kube.ListDelegate {
78 id: delegateRoot
79
80 Kube.Label {
81 anchors {
82 verticalCenter: parent.verticalCenter
83 left: parent.left
84 leftMargin: Kube.Units.largeSpacing
85 }
86 width: parent.width - Kube.Units.largeSpacing * 2
87
88 text: model.name
89 color: delegateRoot.textColor
90 elide: Text.ElideRight
91 }
92 }
93 }
94 }
95
96 Item {
97 height: parent.height
98 width: Kube.Units.gridUnit * 20
99 Layout.fillWidth: true
100
101 Kube.EditAccount {
102 id: edit
103 anchors {
104 fill: parent
105 bottomMargin: Kube.Units.largeSpacing
106 }
107
108 canRemove: !root.singleAccountMode
109
110 Component.onCompleted: {
111 //We don't have any accounts setup if accountId is empty, so we trigger the accountWizard
112 //FIXME: this assumes we load accounts synchronously, which we do right now.
113 if (accountId == "") {
114 //Require the setup to be completed since it's the first account
115 accountWizard.requireSetup = true
116 //Launch account wizard
117 accountWizard.open()
118 }
119 }
120 }
121 }
122 }
123
124 onActiveFocusChanged: {
125 if (activeFocus && accountWizard.visible) {
126 accountWizard.forceActiveFocus()
127 }
128 }
129
130 //BEGIN AccountWizard
131 KubeAccounts.AccountWizard {
132 id: accountWizard
133
134 parent: ApplicationWindow.overlay
135 height: app.height
136 width: app.width - app.sidebarWidth
137 x: app.sidebarWidth
138 y: 0
139
140 availableAccountPlugins: root.availableAccountPlugins
141 }
142 //END AccountWizard
143}
diff --git a/components/kube/qml/AddresseeListEditor.qml b/components/kube/qml/AddresseeListEditor.qml
deleted file mode 100644
index 8f9862e7..00000000
--- a/components/kube/qml/AddresseeListEditor.qml
+++ /dev/null
@@ -1,138 +0,0 @@
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.Layouts 1.1
24
25import org.kube.framework 1.0 as Kube
26
27FocusScope {
28 id: root
29 property variant controller
30 property variant completer
31 property bool encrypt: false
32
33 implicitHeight: listView.height + lineEdit.height
34 height: implicitHeight
35
36 Column {
37 anchors.fill: parent
38
39 spacing: Kube.Units.smallSpacing
40
41 ListView {
42 id: listView
43 anchors {
44 left: parent.left
45 right: parent.right
46 }
47 height: contentHeight
48 spacing: Kube.Units.smallSpacing
49 model: controller.model
50 delegate: Rectangle {
51 height: Kube.Units.gridUnit + Kube.Units.smallSpacing * 2 //smallSpacing for padding
52 width: parent.width
53 color: Kube.Colors.buttonColor
54 Row {
55 anchors {
56 top: parent.top
57 bottom: parent.bottom
58 left: parent.left
59 right: removeButton.left
60 margins: Kube.Units.smallSpacing
61 }
62 spacing: Kube.Units.smallSpacing
63 Kube.Label {
64 id: label
65 anchors {
66 top: parent.top
67 }
68 text: model.name
69 elide: Text.ElideRight
70 }
71 Kube.Icon {
72 anchors {
73 top: parent.top
74 }
75 height: Kube.Units.gridUnit
76 width: height
77 visible: root.encrypt
78 iconName: model.keyFound ? Kube.Icons.secure: Kube.Icons.insecure
79 }
80 }
81 Kube.IconButton {
82 id: removeButton
83 anchors {
84 right: parent.right
85 verticalCenter: parent.verticalCenter
86 margins: Kube.Units.smallSpacing
87 }
88 height: Kube.Units.gridUnit
89 width: height
90 onClicked: root.controller.remove(model.id)
91 padding: 0
92 iconName: Kube.Icons.remove
93 }
94 }
95 }
96
97 FocusScope {
98 height: Kube.Units.gridUnit * Kube.Units.smallSpacing * 2
99 width: parent.width
100 focus: true
101
102 Kube.TextButton {
103 id: button
104 text: "+ " + qsTr("Add recipient")
105 textColor: Kube.Colors.highlightColor
106 focus: true
107 onClicked: {
108 lineEdit.visible = true
109 lineEdit.forceActiveFocus()
110 }
111 }
112
113 Kube.AutocompleteLineEdit {
114 id: lineEdit
115 anchors {
116 left: parent.left
117 right: parent.right
118 }
119 visible: false
120
121 placeholderText: "+ " + qsTr("Add recipient")
122 model: root.completer.model
123 onSearchTermChanged: root.completer.searchString = searchTerm
124 onAccepted: {
125 root.controller.add({name: text});
126 clear()
127 visible = false
128 button.forceActiveFocus()
129 }
130 onAborted: {
131 clear()
132 visible = false
133 button.forceActiveFocus()
134 }
135 }
136 }
137 }
138}
diff --git a/components/kube/qml/ComposerView.qml b/components/kube/qml/ComposerView.qml
deleted file mode 100644
index 1eb88bb4..00000000
--- a/components/kube/qml/ComposerView.qml
+++ /dev/null
@@ -1,533 +0,0 @@
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 QtQuick.Dialogs 1.0 as Dialogs
26
27import org.kube.framework 1.0 as Kube
28
29Kube.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}
diff --git a/components/kube/qml/Kube.qml b/components/kube/qml/Kube.qml
index 9a31ba58..be3f7e34 100644
--- a/components/kube/qml/Kube.qml
+++ b/components/kube/qml/Kube.qml
@@ -86,35 +86,6 @@ Controls2.ApplicationWindow {
86 } 86 }
87 } 87 }
88 88
89 Kube.Listener {
90 filter: Kube.Messages.reply
91 onMessageReceived: {
92 kubeViews.openComposerWithMail(message.mail, false)
93 }
94 }
95
96 Kube.Listener {
97 filter: Kube.Messages.edit
98 onMessageReceived: {
99 kubeViews.openComposerWithMail(message.mail, true)
100 }
101 }
102
103 Kube.Listener {
104 filter: Kube.Messages.compose
105 onMessageReceived: kubeViews.openComposer(true, message.recipients)
106 }
107
108 Kube.Listener {
109 filter: Kube.Messages.requestLogin
110 onMessageReceived: kubeViews.setLoginView(message.accountId)
111 }
112
113 Kube.Listener {
114 filter: Kube.Messages.requestAccountsConfiguration
115 onMessageReceived: kubeViews.setAccountsView()
116 }
117
118 //BEGIN Shortcuts 89 //BEGIN Shortcuts
119 Shortcut { 90 Shortcut {
120 sequence: StandardKey.Quit 91 sequence: StandardKey.Quit
@@ -174,48 +145,20 @@ Controls2.ApplicationWindow {
174 145
175 spacing: Kube.Units.largeSpacing - Kube.Units.smallSpacing 146 spacing: Kube.Units.largeSpacing - Kube.Units.smallSpacing
176 147
177 Kube.IconButton {
178 id: composerButton
179 iconName: Kube.Icons.edit_inverted
180 onClicked: kubeViews.openComposer(false, [])
181 activeFocusOnTab: true
182 checkable: true
183 Controls2.ButtonGroup.group: viewButtonGroup
184 tooltip: qsTr("composer")
185 }
186
187 Kube.IconButton {
188 id: mailButton
189 iconName: Kube.Icons.mail_inverted
190 onClicked: kubeViews.setMailView()
191 activeFocusOnTab: true
192 checkable: true
193 checked: true
194 Controls2.ButtonGroup.group: viewButtonGroup
195 tooltip: qsTr("mails")
196 }
197
198 Kube.IconButton {
199 id: peopleButton
200 iconName: Kube.Icons.user_inverted
201 onClicked: kubeViews.setPeopleView()
202 activeFocusOnTab: true
203 checkable: true
204 Controls2.ButtonGroup.group: viewButtonGroup
205 tooltip: qsTr("people")
206 }
207 Repeater { 148 Repeater {
208 model: Kube.ExtensionModel {} 149 model: Kube.ExtensionModel {
150 id: extensionModel
151 sortOrder: ["composer", "conversation", "people"]
152 }
209 Kube.IconButton { 153 Kube.IconButton {
154 id: button
210 iconName: model.icon 155 iconName: model.icon
211 onClicked: { 156 onClicked: kubeViews.showView(model.name)
212 var component = Qt.createComponent(model.source)
213 kubeViews.pushView(component, {})
214 }
215 activeFocusOnTab: true 157 activeFocusOnTab: true
216 checkable: true 158 checkable: true
217 Controls2.ButtonGroup.group: viewButtonGroup 159 Controls2.ButtonGroup.group: viewButtonGroup
218 tooltip: model.tooltip 160 tooltip: model.tooltip
161 checked: kubeViews.currentViewName == model.name
219 } 162 }
220 } 163 }
221 } 164 }
@@ -240,10 +183,11 @@ Controls2.ApplicationWindow {
240 Kube.IconButton { 183 Kube.IconButton {
241 id: logButton 184 id: logButton
242 iconName: Kube.Icons.info_inverted 185 iconName: Kube.Icons.info_inverted
243 onClicked: kubeViews.setLogView() 186 onClicked: kubeViews.showView("log")
244 activeFocusOnTab: true 187 activeFocusOnTab: true
245 checkable: true 188 checkable: true
246 alert: logView.pendingError 189 alert: kubeViews.getView("log").pendingError
190 checked: kubeViews.currentViewName == "log"
247 Controls2.ButtonGroup.group: viewButtonGroup 191 Controls2.ButtonGroup.group: viewButtonGroup
248 tooltip: qsTr("logview") 192 tooltip: qsTr("logview")
249 } 193 }
@@ -251,141 +195,95 @@ Controls2.ApplicationWindow {
251 Kube.IconButton { 195 Kube.IconButton {
252 id: accountsButton 196 id: accountsButton
253 iconName: Kube.Icons.menu_inverted 197 iconName: Kube.Icons.menu_inverted
254 onClicked: kubeViews.setAccountsView() 198 onClicked: kubeViews.showView("accounts")
255 activeFocusOnTab: true 199 activeFocusOnTab: true
256 checkable: true 200 checkable: true
201 checked: kubeViews.currentViewName == "accounts"
257 Controls2.ButtonGroup.group: viewButtonGroup 202 Controls2.ButtonGroup.group: viewButtonGroup
258 tooltip: qsTr("settings") 203 tooltip: qsTr("settings")
259 } 204 }
260 } 205 }
261 } 206 }
262 Controls2.StackView { 207 ViewManager {
263 id: kubeViews 208 id: kubeViews
264
265 anchors { 209 anchors {
266 top: mainContent.top 210 top: mainContent.top
267 bottom: mainContent.bottom 211 bottom: mainContent.bottom
268 } 212 }
269 Layout.fillWidth: true 213 Layout.fillWidth: true
270 214
271 Kube.Listener { 215 extensionModel: extensionModel
272 filter: Kube.Messages.componentDone
273 onMessageReceived: {
274 //Return to the mailview if we try to pop everything off
275 if (kubeViews.depth == 1) {
276 kubeViews.setMailView()
277 } else {
278 kubeViews.pop(Controls2.StackView.Immediate)
279 }
280 }
281 }
282
283 onCurrentItemChanged: {
284 if (currentItem) {
285 currentItem.forceActiveFocus()
286 }
287 }
288 216
289 Component.onCompleted: { 217 Component.onCompleted: {
290 //Setup the initial item stack 218 dontFocus = true
291 if (!currentItem) { 219 showView("conversation")
292 setMailView() 220 if (startupCheck.noAccount) {
293 if (startupCheck.noAccount) { 221 showView("accounts")
294 setAccountsView()
295 }
296 } 222 }
223 dontFocus = false
297 } 224 }
298 225
299 ///Replace the current view (we can't go back to the old view, and we destroy the old view) 226 Kube.Listener {
300 function replaceView(view) { 227 filter: Kube.Messages.reply
301 if (currentItem != view) { 228 onMessageReceived: kubeViews.replaceView("composer", {message: message.mail, loadAsDraft: false})
302 kubeViews.replace(null, view, {}, Controls2.StackView.Immediate)
303 }
304 }
305
306 ///Push a new view on the stack (the old view remains, and we can go back once done)
307 function pushView(view, properties) {
308 kubeViews.push(view, properties, Controls2.StackView.Immediate)
309 }
310
311 //TODO replacing here while a composer is open is destructive
312 function setPeopleView() {
313 replaceView(peopleView)
314 } 229 }
315 230
316 function setMailView() { 231 Kube.Listener {
317 replaceView(mailView) 232 filter: Kube.Messages.edit
233 onMessageReceived: kubeViews.replaceView("composer", {message: message.mail, loadAsDraft: true})
318 } 234 }
319 235
320 function setAccountsView() { 236 Kube.Listener {
321 pushView(accountsView, {}) 237 filter: Kube.Messages.compose
238 onMessageReceived: kubeViews.replaceView("composer", {newMessage: true, recipients: message.recipients})
322 } 239 }
323 240
324 function setLogView() { 241 Kube.Listener {
325 replaceView(logView) 242 filter: Kube.Messages.requestAccountsConfiguration
243 onMessageReceived: kubeViews.showView("accounts")
326 } 244 }
327 245
328 function setLoginView(account) { 246 Kube.Listener {
329 if (currentItem != loginView) { 247 filter: Kube.Messages.componentDone
330 pushView(loginView, {accountId: account}) 248 onMessageReceived: {
249 kubeViews.closeView()
331 } 250 }
332 } 251 }
333 252
334 function openComposer(newMessage, recipients) { 253 Kube.Listener {
335 pushView(composerView, {newMessage: newMessage, recipients: recipients}) 254 filter: Kube.Messages.requestLogin
336 } 255 onMessageReceived: {
337 256 loginView.createObject(kubeViews, {accountId: message.accountId})
338 function openComposerWithMail(mail, openAsDraft) {
339 pushView(composerView, {message: mail, loadAsDraft: openAsDraft})
340 }
341
342
343 //These items are not visible until pushed onto the stack, so we keep them in resources instead of items
344 resources: [
345 //Not components so we maintain state
346 MailView {
347 id: mailView
348 anchors.fill: parent
349 Controls2.StackView.onActivated: mailButton.checked = true
350 Controls2.StackView.onDeactivated: mailButton.checked = false
351 },
352 PeopleView {
353 id: peopleView
354 anchors.fill: parent
355 Controls2.StackView.onActivated: peopleButton.checked = true
356 Controls2.StackView.onDeactivated: peopleButton.checked = false
357 },
358 //Not a component because otherwise we can't log stuff
359 LogView {
360 id: logView
361 anchors.fill: parent
362 Controls2.StackView.onActivated: logButton.checked = true
363 Controls2.StackView.onDeactivated: logButton.checked = false
364 }
365 ]
366 //A component so it's always destroyed when we're done
367 Component {
368 id: composerView
369 ComposerView {
370 anchors.fill: parent
371 Controls2.StackView.onActivated: composerButton.checked = true
372 Controls2.StackView.onDeactivated: composerButton.checked = false
373 }
374 }
375 Component {
376 id: accountsView
377 AccountsView {
378 anchors.fill: parent
379 Controls2.StackView.onActivated: accountsButton.checked = true
380 Controls2.StackView.onDeactivated: accountsButton.checked = false
381 } 257 }
382 } 258 }
259
383 Component { 260 Component {
384 id: loginView 261 id: loginView
385 LoginView { 262 Kube.Popup {
386 anchors.fill: parent 263 id: popup
264 property alias accountId: login.accountId
265 visible: true
266 parent: Controls2.ApplicationWindow.overlay
267 height: app.height
268 width: app.width - app.sidebarWidth
269 x: app.sidebarWidth
270 y: 0
271 modal: true
272 closePolicy: Controls2.Popup.NoAutoClose
273 Kube.LoginAccount {
274 id: login
275 anchors {
276 fill: parent
277 bottomMargin: Kube.Units.largeSpacing
278 }
279 onDone: {
280 popup.close()
281 kubeViews.currentItem.forceActiveFocus()
282 }
283 }
387 } 284 }
388 } 285 }
286
389 } 287 }
390 } 288 }
391 //END Main content 289 //END Main content
diff --git a/components/kube/qml/LogView.qml b/components/kube/qml/LogView.qml
deleted file mode 100644
index 4ae1a67c..00000000
--- a/components/kube/qml/LogView.qml
+++ /dev/null
@@ -1,329 +0,0 @@
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
20import QtQuick 2.4
21import QtQuick.Layouts 1.1
22import QtQuick.Controls 1.3 as Controls
23import QtQuick.Controls 2.0 as Controls2
24import org.kube.framework 1.0 as Kube
25
26Controls.SplitView {
27 id: root
28
29 property bool pendingError: false;
30
31 Controls2.StackView.onActivated: {
32 root.pendingError = false;
33 //Always select the latest notification
34 listView.currentIndex = 0
35 }
36
37 Item {
38 id: accountList
39 width: parent.width/3
40 Layout.fillHeight: true
41
42 Kube.Listener {
43 filter: Kube.Messages.notification
44 onMessageReceived: {
45 if (message.type == Kube.Notifications.error) {
46 root.pendingError = true
47 }
48 var error = {timestamp: new Date(), message: message.message, details: message.details, resource: message.resource}
49 if (logModel.count > 0) {
50 var lastEntry = logModel.get(0)
51 //Merge if we get an entry of the same subtype
52 if (lastEntry.subtype && lastEntry.subtype == message.subtype) {
53 logModel.set(0, {type: message.type, subtype: message.subtype, errors: [error].concat(lastEntry.errors)})
54 return
55 }
56 }
57 logModel.insert(0, {type: message.type, subtype: message.subtype, errors: [error]})
58 }
59 }
60
61 Kube.Label {
62 anchors.centerIn: parent
63 visible: listView.count == 0
64 text: qsTr("Nothing here...")
65 }
66
67 Kube.ListView {
68 id: listView
69 anchors {
70 fill: parent
71 }
72
73 clip: true
74
75 model: ListModel {
76 id: logModel
77 objectName: "logModel"
78 }
79
80 onCurrentItemChanged: {
81 var error = currentItem.currentData.errors.get(0)
82 if (!!error.resource) {
83 details.resourceId = error.resource
84 }
85 details.message = error.message + "\n" + error.details
86 details.timestamp = error.timestamp
87 if (!!currentItem.currentData.subtype) {
88 details.subtype = currentItem.currentData.subtype
89 } else {
90 details.subtype = ""
91 }
92 }
93
94 delegate: Kube.ListDelegate {
95 border.color: Kube.Colors.buttonColor
96 border.width: 1
97 Kube.Label {
98 id: description
99 anchors {
100 top: parent.top
101 topMargin: Kube.Units.smallSpacing
102 left: parent.left
103 leftMargin: Kube.Units.largeSpacing
104 }
105 height: Kube.Units.gridUnit
106 width: parent.width - Kube.Units.largeSpacing * 2
107 text: model.type == Kube.Notifications.error ? qsTr("Error") : qsTr("Info")
108 }
109
110 Kube.Label {
111 id: message
112 anchors {
113 topMargin: Kube.Units.smallSpacing
114 top: description.bottom
115 left: parent.left
116 leftMargin: Kube.Units.largeSpacing
117 }
118 height: Kube.Units.gridUnit
119 width: parent.width - Kube.Units.largeSpacing * 2
120 maximumLineCount: 1
121 elide: Text.ElideRight
122 color: Kube.Colors.disabledTextColor
123 text: model.errors.get(0).message
124 }
125
126 Kube.Label {
127 id: date
128
129 anchors {
130 right: parent.right
131 bottom: parent.bottom
132 rightMargin: Kube.Units.smallSpacing
133 }
134 text: Qt.formatDateTime(model.errors.get(0).timestamp, " hh:mm:ss dd MMM yyyy")
135 font.italic: true
136 color: Kube.Colors.disabledTextColor
137 font.pointSize: Kube.Units.smallFontSize
138 }
139 }
140 }
141 }
142 Item {
143 id: details
144 property string subtype: ""
145 property date timestamp
146 property string message: ""
147 property string resourceId: ""
148
149 Kube.ModelIndexRetriever {
150 id: retriever
151 model: Kube.AccountsModel {
152 resourceId: details.resourceId
153 }
154 }
155
156 Loader {
157 id: detailsLoader
158 visible: message != ""
159 clip: true
160 anchors {
161 fill: parent
162 margins: Kube.Units.largeSpacing
163 }
164 property date timestamp: details.timestamp
165 property string message: details.message
166 property string resourceId: details.resourceId
167 property string accountId: retriever.currentData ? retriever.currentData.accountId : ""
168 property string accountName: retriever.currentData ? retriever.currentData.name : ""
169
170 function getComponent(subtype) {
171 if (subtype == Kube.Notifications.loginError) {
172 return loginErrorComponent
173 }
174 if (subtype == Kube.Notifications.hostNotFoundError) {
175 return hostNotFoundErrorComponent
176 }
177 if (subtype == Kube.Notifications.connectionError) {
178 return hostNotFoundErrorComponent
179 }
180 return detailsComponent
181 }
182
183 sourceComponent: getComponent(details.subtype)
184 }
185 }
186
187 Component {
188 id: detailsComponent
189 Rectangle {
190 color: Kube.Colors.viewBackgroundColor
191 GridLayout {
192 id: gridLayout
193 Layout.minimumWidth: 0
194 anchors {
195 top: parent.top
196 left: parent.left
197 right: parent.right
198 }
199 columns: 2
200 Kube.Label {
201 text: qsTr("Account:")
202 visible: accountName
203 }
204 Kube.Label {
205 Layout.fillWidth: true
206 text: accountName
207 visible: accountName
208 elide: Text.ElideRight
209 }
210 Kube.Label {
211 text: qsTr("Account Id:")
212 visible: accountId
213 }
214 Kube.Label {
215 text: accountId
216 visible: accountId
217 Layout.fillWidth: true
218 elide: Text.ElideRight
219 }
220 Kube.Label {
221 text: qsTr("Resource Id:")
222 visible: resourceId
223 }
224 Kube.Label {
225 text: resourceId
226 visible: resourceId
227 Layout.fillWidth: true
228 elide: Text.ElideRight
229 }
230 Kube.Label {
231 text: qsTr("Timestamp:")
232 }
233 Kube.Label {
234 text: Qt.formatDateTime(timestamp, " hh:mm:ss dd MMM yyyy")
235 Layout.fillWidth: true
236 elide: Text.ElideRight
237 }
238 Kube.Label {
239 text: qsTr("Message:")
240 Layout.alignment: Qt.AlignTop
241 }
242 Kube.Label {
243 text: message
244 Layout.fillWidth: true
245 wrapMode: Text.Wrap
246 }
247 Item {
248 Layout.columnSpan: 2
249 Layout.fillHeight: true
250 Layout.fillWidth: true
251 }
252 }
253
254 Kube.SelectableItem {
255 layout: gridLayout
256 }
257 }
258 }
259
260 Component {
261 id: loginErrorComponent
262 Item {
263 Column {
264 anchors {
265 top: parent.top
266 left: parent.left
267 right: parent.right
268 }
269 spacing: Kube.Units.largeSpacing
270 Column {
271 Kube.Heading {
272 id: heading
273 text: qsTr("Failed to login")
274 color: Kube.Colors.warningColor
275 }
276
277 Kube.Label {
278 id: subHeadline
279 text: accountName + ": " + qsTr("Please check your credentials.")
280 color: Kube.Colors.disabledTextColor
281 wrapMode: Text.Wrap
282 }
283 }
284 Kube.Button {
285 text: qsTr("Change Password")
286 onClicked: {
287 Kube.Fabric.postMessage(Kube.Messages.componentDone, {})
288 Kube.Fabric.postMessage(Kube.Messages.requestLogin, {accountId: accountId})
289 }
290 }
291 }
292 }
293 }
294
295 Component {
296 id: hostNotFoundErrorComponent
297 Item {
298 Column {
299 anchors {
300 top: parent.top
301 left: parent.left
302 right: parent.right
303 }
304 spacing: Kube.Units.largeSpacing
305 Column {
306 Kube.Heading {
307 id: heading
308 text: qsTr("Host not found")
309 color: Kube.Colors.warningColor
310 }
311
312 Kube.Label {
313 id: subHeadline
314 text: accountName + ": " + qsTr("Please check your network connection and settings.")
315 color: Kube.Colors.disabledTextColor
316 wrapMode: Text.Wrap
317 }
318 }
319 Kube.Button {
320 text: qsTr("Account settings")
321 onClicked: {
322 Kube.Fabric.postMessage(Kube.Messages.componentDone, {})
323 Kube.Fabric.postMessage(Kube.Messages.requestAccountsConfiguration, {})
324 }
325 }
326 }
327 }
328 }
329}
diff --git a/components/kube/qml/LoginView.qml b/components/kube/qml/LoginView.qml
deleted file mode 100644
index dbbed11c..00000000
--- a/components/kube/qml/LoginView.qml
+++ /dev/null
@@ -1,52 +0,0 @@
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
20import QtQuick 2.4
21import QtQuick.Layouts 1.1
22import QtQuick.Controls 2.0
23import org.kube.framework 1.0 as Kube
24
25FocusScope {
26 id: root
27 property alias accountId: login.accountId
28 onActiveFocusChanged: {
29 if (activeFocus) {
30 popup.forceActiveFocus()
31 }
32 }
33
34 Kube.Popup {
35 id: popup
36 visible: true
37 parent: ApplicationWindow.overlay
38 height: app.height
39 width: app.width - app.sidebarWidth
40 x: app.sidebarWidth
41 y: 0
42 modal: true
43 closePolicy: Popup.NoAutoClose
44 Kube.LoginAccount {
45 id: login
46 anchors {
47 fill: parent
48 bottomMargin: Kube.Units.largeSpacing
49 }
50 }
51 }
52}
diff --git a/components/kube/qml/MailView.qml b/components/kube/qml/MailView.qml
deleted file mode 100644
index 8b2b0caf..00000000
--- a/components/kube/qml/MailView.qml
+++ /dev/null
@@ -1,120 +0,0 @@
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
25
26import org.kube.framework 1.0 as Kube
27
28FocusScope {
29 SplitView {
30 anchors.fill: parent
31 Rectangle {
32 width: Kube.Units.gridUnit * 10
33 Layout.fillHeight: parent.height
34 color: Kube.Colors.textColor
35
36 Kube.PositiveButton {
37 id: newMailButton
38
39 anchors {
40 top: parent.top
41 left: parent.left
42 right: parent.right
43 margins: Kube.Units.largeSpacing
44 }
45 focus: true
46 text: qsTr("New Email")
47 onClicked: Kube.Fabric.postMessage(Kube.Messages.compose, {})
48 }
49
50 Kube.InlineAccountSwitcher {
51 id: accountFolderview
52 activeFocusOnTab: true
53 anchors {
54 top: newMailButton.bottom
55 topMargin: Kube.Units.largeSpacing
56 bottom: statusBarContainer.top
57 left: newMailButton.left
58 right: parent.right
59 }
60 }
61
62 Item {
63 id: statusBarContainer
64 anchors {
65 topMargin: Kube.Units.smallSpacing
66 bottom: parent.bottom
67 left: parent.left
68 right: parent.right
69 }
70 height: childrenRect.height
71
72 Rectangle {
73 id: border
74 visible: statusBar.visible
75 anchors {
76 right: parent.right
77 left: parent.left
78 margins: Kube.Units.smallSpacing
79 }
80 height: 1
81 color: Kube.Colors.viewBackgroundColor
82 opacity: 0.3
83 }
84 Kube.StatusBar {
85 id: statusBar
86 accountId: accountFolderview.currentAccount
87 height: Kube.Units.gridUnit * 2
88 anchors {
89 top: border.bottom
90 left: statusBarContainer.left
91 right: statusBarContainer.right
92 }
93 }
94 }
95 }
96
97 Rectangle {
98 width: Kube.Units.gridUnit * 18
99 Layout.fillHeight: parent.height
100
101 color: "transparent"
102 border.width: 1
103 border.color: Kube.Colors.buttonColor
104
105 Kube.MailListView {
106 id: mailListView
107 anchors.fill: parent
108 activeFocusOnTab: true
109 Layout.minimumWidth: Kube.Units.gridUnit * 10
110 }
111 }
112
113 Kube.ConversationView {
114 id: mailView
115 Layout.fillWidth: true
116 Layout.fillHeight: parent.height
117 activeFocusOnTab: true
118 }
119 }
120}
diff --git a/components/kube/qml/PeopleView.qml b/components/kube/qml/PeopleView.qml
deleted file mode 100644
index 3f1b9261..00000000
--- a/components/kube/qml/PeopleView.qml
+++ /dev/null
@@ -1,38 +0,0 @@
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 2.1
23import org.kube.framework 1.0 as Kube
24
25Item {
26
27 StackView.onActivated: {
28 Kube.Fabric.postMessage(Kube.Messages.synchronize, {"type": "contacts"})
29 }
30
31 Kube.People {
32 id: people
33 anchors {
34 fill: parent
35 margins: Kube.Units.smallSpacing
36 }
37 }
38}
diff --git a/components/kube/qml/ViewManager.qml b/components/kube/qml/ViewManager.qml
new file mode 100644
index 00000000..6874107a
--- /dev/null
+++ b/components/kube/qml/ViewManager.qml
@@ -0,0 +1,84 @@
1/*
2 * Copyright (C) 2018 Christian Mollekopf, <mollekopf@kolabsys.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19
20import QtQuick 2.7
21import QtQuick.Controls 2.0
22/*
23* TODO
24* * Only replace composer if necessary (on reply, edit draft, ...)
25* * Shutdown procedure to save draft before destruction
26* * Separate logging from view and and make accessible to log (initialize()) call?
27*/
28StackView {
29 id: root
30 property string currentViewName: currentItem ? currentItem.objectName : ""
31 property variant extensionModel: null
32 property bool dontFocus: false
33
34 property var viewDict: new Object
35 function getView(name, replaceView) {
36 if (!replaceView && name in viewDict) {
37 var item = viewDict[name]
38 if (item) {
39 return item
40 }
41 }
42 var v = Qt.createComponent(extensionModel.findSource(name, "View.qml"))
43 v = v.createObject(root)
44 viewDict[name] = v
45 return v;
46 }
47
48 onCurrentItemChanged: {
49 if (currentItem && !dontFocus) {
50 currentItem.forceActiveFocus()
51 }
52 }
53
54 function showOrReplaceView(name, properties, replace) {
55 if (currentItem && currentItem.objectName == name) {
56 return
57 }
58 if (root.depth > 0) {
59 root.pop(StackView.Immediate)
60 }
61 var view = getView(name, replace)
62 var item = push(view, properties, StackView.Immediate)
63 item.parent = root
64 item.anchors.fill = root
65 item.objectName = name
66 }
67
68 function showView(name, properties) {
69 showOrReplaceView(name, properties, false)
70 }
71
72 function replaceView(name, properties) {
73 showOrReplaceView(name, properties, true)
74 }
75
76 function closeView() {
77 //The initial view remains
78 if (kubeViews.depth > 1) {
79 var item = kubeViews.pop(StackView.Immediate)
80 viewDict[item.objectName] = null
81 item.destroy()
82 }
83 }
84}
diff --git a/components/kube/tests/tst_accountsview.qml b/components/kube/tests/tst_accountsview.qml
deleted file mode 100644
index 428bb4cc..00000000
--- a/components/kube/tests/tst_accountsview.qml
+++ /dev/null
@@ -1,37 +0,0 @@
1/*
2 * Copyright 2017 Christian Mollekopf <mollekopf@kolabsys.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Library General Public License as
6 * published by the Free Software Foundation; either version 2, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Library General Public License for more details
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this program; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20import QtQuick 2.7
21import QtTest 1.0
22import "../qml"
23
24TestCase {
25 id: testCase
26 width: 400
27 height: 400
28 name: "AccountsView"
29
30 AccountsView {
31 id: accountsView
32 }
33
34 function test_start() {
35 verify(accountsView)
36 }
37}
diff --git a/components/kube/tests/tst_composerview.qml b/components/kube/tests/tst_composerview.qml
deleted file mode 100644
index 67db6ef6..00000000
--- a/components/kube/tests/tst_composerview.qml
+++ /dev/null
@@ -1,97 +0,0 @@
1/*
2 * Copyright 2017 Christian Mollekopf <mollekopf@kolabsys.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Library General Public License as
6 * published by the Free Software Foundation; either version 2, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Library General Public License for more details
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this program; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20import QtQuick 2.7
21import QtTest 1.0
22import "../qml"
23import org.kube.framework 1.0 as Kube
24import org.kube.test 1.0
25
26TestCase {
27 id: testCase
28 width: 400
29 height: 400
30 name: "ComposerView"
31 when: windowShown
32
33 Component {
34 id:composerComponent
35 ComposerView {
36 focus: true
37 }
38 }
39
40 function test_1start() {
41 var composer = createTemporaryObject(composerComponent, testCase, {})
42 verify(composer)
43 }
44
45 function test_2verifyInitialFocus() {
46 var composer = createTemporaryObject(composerComponent, testCase, {})
47 var newMailButton = findChild(composer, "newMailButton");
48 verify(newMailButton)
49 verify(newMailButton.activeFocus)
50 }
51
52 function test_3sendMessage() {
53 var initialState = {
54 accounts: [{
55 id: "account1",
56 }],
57 identities: [{
58 account: "account1",
59 name: "Test Identity",
60 address: "identity@example.org"
61 }],
62 resources: [{
63 id: "resource1",
64 account: "account1",
65 type: "dummy"
66 },
67 {
68 id: "resource2",
69 account: "account1",
70 type: "mailtransport"
71 }],
72 mails:[{
73 resource: "resource1",
74 subject: "subject",
75 body: "body",
76 to: ["to@example.org"],
77 cc: ["cc@example.org"],
78 bcc: ["bcc@example.org"],
79 draft: true
80 }]
81 }
82 TestStore.setup(initialState)
83 var composer = createTemporaryObject(composerComponent, testCase, {})
84
85 var createdMail = TestStore.load("mail", {resource: "resource1"})
86
87 var loadAsDraft = true
88 composer.loadMessage(createdMail, loadAsDraft)
89 var sendMailButton = findChild(composer, "sendButton")
90 verify(sendMailButton)
91 tryVerify(function(){ return sendMailButton.enabled })
92 sendMailButton.clicked()
93
94 tryVerify(function(){ return TestStore.load("mail", {resource: "resource2"}) })
95 tryVerify(function(){ return !TestStore.load("mail", {resource: "resource1"}) })
96 }
97}
diff --git a/components/kube/tests/tst_logview.qml b/components/kube/tests/tst_logview.qml
deleted file mode 100644
index d3326db1..00000000
--- a/components/kube/tests/tst_logview.qml
+++ /dev/null
@@ -1,65 +0,0 @@
1/*
2 * Copyright 2017 Christian Mollekopf <mollekopf@kolabsys.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Library General Public License as
6 * published by the Free Software Foundation; either version 2, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Library General Public License for more details
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this program; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20import QtQuick 2.7
21import QtQuick.Controls 2.0
22import QtQuick.Window 2.1
23import QtTest 1.0
24import org.kube.framework 1.0 as Kube
25import "../qml"
26
27TestCase {
28 id: logviewTestcase
29 width: 400
30 height: 400
31 name: "LogView"
32
33 LogView {
34 id: logView
35 }
36
37 function test_logview() {
38 var listModel = findChild(logView, "logModel");
39 verify(listModel)
40 compare(listModel.count, 0)
41 //ignore progress
42 Kube.Fabric.postMessage(Kube.Messages.progressNotification, {})
43 compare(listModel.count, 0)
44
45 Kube.Fabric.postMessage(Kube.Messages.notification, {type: Kube.Notifications.info, message: "foobar", resource: "resource"})
46 compare(listModel.count, 1)
47 compare(logView.pendingError, false)
48
49 Kube.Fabric.postMessage(Kube.Messages.notification, {"type": Kube.Notifications.error, message: "foobar", resource: "resource"})
50 compare(listModel.count, 2)
51 compare(logView.pendingError, true)
52 compare(listModel.get(0).type, Kube.Notifications.error)
53 compare(listModel.get(0).errors.count, 1)
54 compare(listModel.get(0).errors.get(0).message, "foobar")
55 compare(listModel.get(0).errors.get(0).resource, "resource")
56
57 Kube.Fabric.postMessage(Kube.Messages.notification, {"type": Kube.Notifications.error, "subtype": "merge", message: "merge1", resource: "resource1"})
58 compare(listModel.count, 3)
59 Kube.Fabric.postMessage(Kube.Messages.notification, {"type": Kube.Notifications.error, "subtype": "merge", message: "merge2", resource: "resource2"})
60 compare(listModel.count, 3)
61 compare(listModel.get(0).errors.count, 2)
62 compare(listModel.get(0).errors.get(0).message, "merge2")
63 compare(listModel.get(0).errors.get(0).resource, "resource2")
64 }
65}
diff --git a/components/kube/tests/tst_mailview.qml b/components/kube/tests/tst_mailview.qml
deleted file mode 100644
index f31d574d..00000000
--- a/components/kube/tests/tst_mailview.qml
+++ /dev/null
@@ -1,37 +0,0 @@
1/*
2 * Copyright 2017 Christian Mollekopf <mollekopf@kolabsys.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Library General Public License as
6 * published by the Free Software Foundation; either version 2, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Library General Public License for more details
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this program; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20import QtQuick 2.7
21import QtTest 1.0
22import "../qml"
23
24TestCase {
25 id: testCase
26 width: 400
27 height: 400
28 name: "MailView"
29
30 MailView {
31 id: mailView
32 }
33
34 function test_start() {
35 verify(mailView)
36 }
37}
diff --git a/components/kube/tests/tst_peopleview.qml b/components/kube/tests/tst_peopleview.qml
deleted file mode 100644
index e224b527..00000000
--- a/components/kube/tests/tst_peopleview.qml
+++ /dev/null
@@ -1,37 +0,0 @@
1/*
2 * Copyright 2017 Christian Mollekopf <mollekopf@kolabsys.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Library General Public License as
6 * published by the Free Software Foundation; either version 2, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Library General Public License for more details
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this program; if not, write to the
16 * Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19
20import QtQuick 2.7
21import QtTest 1.0
22import "../qml"
23
24TestCase {
25 id: testCase
26 width: 400
27 height: 400
28 name: "PeopleView"
29
30 PeopleView {
31 id: peopleView
32 }
33
34 function test_start() {
35 verify(peopleView)
36 }
37}