summaryrefslogtreecommitdiffstats
path: root/views
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 /views
parent2d9944bd0b5cd1dd202d9dc6318d612e1aca4241 (diff)
downloadkube-6d726bb10386b3d7f5481d41b735ec06cb2163ad.tar.gz
kube-6d726bb10386b3d7f5481d41b735ec06cb2163ad.zip
Install composer/converations/people as separate views and load them
dynamically.
Diffstat (limited to 'views')
-rw-r--r--views/CMakeLists.txt11
-rw-r--r--views/accounts/metadata.json4
-rw-r--r--views/accounts/qml/View.qml143
-rw-r--r--views/accounts/tests/tst_accountsview.qml37
-rw-r--r--views/composer/metadata.json4
-rw-r--r--views/composer/qml/AddresseeListEditor.qml138
-rw-r--r--views/composer/qml/View.qml533
-rw-r--r--views/composer/tests/tst_composerview.qml97
-rw-r--r--views/conversation/metadata.json4
-rw-r--r--views/conversation/qml/View.qml120
-rw-r--r--views/conversation/tests/tst_conversationview.qml37
-rw-r--r--views/log/metadata.json4
-rw-r--r--views/log/qml/View.qml329
-rw-r--r--views/log/tests/tst_logview.qml65
-rw-r--r--views/people/metadata.json4
-rw-r--r--views/people/qml/View.qml38
-rw-r--r--views/people/tests/tst_peopleview.qml37
17 files changed, 1605 insertions, 0 deletions
diff --git a/views/CMakeLists.txt b/views/CMakeLists.txt
new file mode 100644
index 00000000..4004e310
--- /dev/null
+++ b/views/CMakeLists.txt
@@ -0,0 +1,11 @@
1macro(install_view name)
2 install(DIRECTORY ${name}/qml/ DESTINATION ${QML_INSTALL_DIR}/org/kube/views/${name})
3 install(FILES ${name}/metadata.json DESTINATION ${QML_INSTALL_DIR}/org/kube/views/${name})
4 add_test(NAME viewtest-${name} COMMAND kubetestrunner WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${name}/tests)
5endmacro()
6
7install_view(composer)
8install_view(conversation)
9install_view(people)
10install_view(log)
11install_view(accounts)
diff --git a/views/accounts/metadata.json b/views/accounts/metadata.json
new file mode 100644
index 00000000..55091f97
--- /dev/null
+++ b/views/accounts/metadata.json
@@ -0,0 +1,4 @@
1{
2 "tooltip": "Account configuration.",
3 "hidden": true
4}
diff --git a/views/accounts/qml/View.qml b/views/accounts/qml/View.qml
new file mode 100644
index 00000000..9b774907
--- /dev/null
+++ b/views/accounts/qml/View.qml
@@ -0,0 +1,143 @@
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/views/accounts/tests/tst_accountsview.qml b/views/accounts/tests/tst_accountsview.qml
new file mode 100644
index 00000000..096ca9eb
--- /dev/null
+++ b/views/accounts/tests/tst_accountsview.qml
@@ -0,0 +1,37 @@
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 View {
31 id: accountsView
32 }
33
34 function test_start() {
35 verify(accountsView)
36 }
37}
diff --git a/views/composer/metadata.json b/views/composer/metadata.json
new file mode 100644
index 00000000..c4654fba
--- /dev/null
+++ b/views/composer/metadata.json
@@ -0,0 +1,4 @@
1{
2 "icon": "document-edit-inverted",
3 "tooltip": "Compose new messages."
4}
diff --git a/views/composer/qml/AddresseeListEditor.qml b/views/composer/qml/AddresseeListEditor.qml
new file mode 100644
index 00000000..8f9862e7
--- /dev/null
+++ b/views/composer/qml/AddresseeListEditor.qml
@@ -0,0 +1,138 @@
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/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
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/views/composer/tests/tst_composerview.qml b/views/composer/tests/tst_composerview.qml
new file mode 100644
index 00000000..eac391c1
--- /dev/null
+++ b/views/composer/tests/tst_composerview.qml
@@ -0,0 +1,97 @@
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 View {
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/views/conversation/metadata.json b/views/conversation/metadata.json
new file mode 100644
index 00000000..870ff2aa
--- /dev/null
+++ b/views/conversation/metadata.json
@@ -0,0 +1,4 @@
1{
2 "icon": "mail-message-inverted",
3 "tooltip": "Follow conversations."
4}
diff --git a/views/conversation/qml/View.qml b/views/conversation/qml/View.qml
new file mode 100644
index 00000000..8b2b0caf
--- /dev/null
+++ b/views/conversation/qml/View.qml
@@ -0,0 +1,120 @@
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/views/conversation/tests/tst_conversationview.qml b/views/conversation/tests/tst_conversationview.qml
new file mode 100644
index 00000000..467c049a
--- /dev/null
+++ b/views/conversation/tests/tst_conversationview.qml
@@ -0,0 +1,37 @@
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 View {
31 id: mailView
32 }
33
34 function test_start() {
35 verify(mailView)
36 }
37}
diff --git a/views/log/metadata.json b/views/log/metadata.json
new file mode 100644
index 00000000..1bcba1fb
--- /dev/null
+++ b/views/log/metadata.json
@@ -0,0 +1,4 @@
1{
2 "tooltip": "Log messages.",
3 "hidden": true
4}
diff --git a/views/log/qml/View.qml b/views/log/qml/View.qml
new file mode 100644
index 00000000..4ae1a67c
--- /dev/null
+++ b/views/log/qml/View.qml
@@ -0,0 +1,329 @@
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/views/log/tests/tst_logview.qml b/views/log/tests/tst_logview.qml
new file mode 100644
index 00000000..a78d71cb
--- /dev/null
+++ b/views/log/tests/tst_logview.qml
@@ -0,0 +1,65 @@
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 View {
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/views/people/metadata.json b/views/people/metadata.json
new file mode 100644
index 00000000..44296a7e
--- /dev/null
+++ b/views/people/metadata.json
@@ -0,0 +1,4 @@
1{
2 "icon": "im-user-inverted",
3 "tooltip": "Your contacts."
4}
diff --git a/views/people/qml/View.qml b/views/people/qml/View.qml
new file mode 100644
index 00000000..3f1b9261
--- /dev/null
+++ b/views/people/qml/View.qml
@@ -0,0 +1,38 @@
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/views/people/tests/tst_peopleview.qml b/views/people/tests/tst_peopleview.qml
new file mode 100644
index 00000000..263247ad
--- /dev/null
+++ b/views/people/tests/tst_peopleview.qml
@@ -0,0 +1,37 @@
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 View {
31 id: peopleView
32 }
33
34 function test_start() {
35 verify(peopleView)
36 }
37}