Dekko
Loading...
Searching...
No Matches
DefaultMessagePage.qml
1/* Copyright (C) 2016 - 2017 Dan Chapman <dpniel@ubuntu.com>
2
3 This file is part of Dekko email client for Ubuntu devices
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License as
7 published by the Free Software Foundation; either version 2 of
8 the License or (at your option) version 3
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
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18import QtQuick 2.4
19import QtQuick.Controls.Suru 2.2
20import Lomiri.Components 1.3
21import Lomiri.Components.Popups 1.3
22import QtWebEngine 1.5
23import Dekko.Mail 1.0
24import Dekko.Components 1.0
25import Dekko.Mail.Settings 1.0
26import Dekko.Mail.API 1.0
27import Dekko.Mail.Stores.Views 1.0
28import Dekko.Lomiri.Components 1.0
29import "../components"
30import "../webview"
31import "../composer"
32import Dekko.Lomiri.Constants 1.0
33
34DekkoPage {
35
36 // Hide the default header
37 pageHeader.showDivider: false
38 pageHeader.visible: false
39
40 DefaultMessagePageHeader {
41 id: msgPgHeader
42 anchors {
43 left: parent.left
44 top: parent.top
45 right: parent.right
46 }
47 msg: message
48 }
49
50 property alias msgId: message.messageId
51
52 Connections {
53 target: ViewStore
54 onFormFactorChanged: {
55 if ((ViewStore.formFactor !== "small") && (stageArea.stageID === ViewKeys.messageListStack)) {
56 ViewActions.switchMessageViewLocation(ViewKeys.messageListStack, msgId)
57 } else if ((ViewStore.formFactor === "small") && (stageArea.stageID === ViewKeys.messageViewStack)) {
58 ViewActions.switchMessageViewLocation(ViewKeys.messageViewStack, msgId)
59 }
60 }
61 }
62
63 Message {
64 id: message
65 onBodyChanged: {
66 webview.setCidQuery(message.messageId)
67 webview.setBodyUrl(body)
68 if (!message.isRead) {
69 switch(mailPolicy.markRead) {
70 case MailPolicy.Never:
71 Log.logInfo("DefaultMessagePage::onBodyChanged", "Not marking message as read");
72 break; // do nothing
73 case MailPolicy.AfterInterval:
74 Log.logInfo("DefaultMessagePage::onBodyChanged", "Marking message read after interval");
75 markReadTimer.start()
76 break
77 case MailPolicy.Immediately:
78 Log.logInfo("DefaultMessagePage::onBodyChanged", "Marking message read immediately");
79 MessageActions.markMessageRead(message.messageId, true)
80 break
81 }
82 }
83 }
84 }
85
86 MailPolicy {
87 id: mailPolicy
88 accountId: message.parentAccountId
89 }
90
91 Timer {
92 id: markReadTimer
93 interval: mailPolicy.markAsReadInterval
94 repeat: false
95 onTriggered: MessageActions.markMessageRead(message.messageId, true)
96 }
97
98 ContentBlockedNotice {
99 id: contentBlockedItem
100 contentBlocked: webview.contentBlocked
101 anchors {
102 left: parent.left
103 top: msgPgHeader.bottom
104 right: parent.right
105 }
106 onAllowClicked: webview.allowBlockedContent()
107 }
108
109 Item {
110 id: container
111 clip: true
112 anchors {
113 left: parent.left
114 right: parent.right
115 top: contentBlockedItem.bottom
116 bottom: hiddenMargin.top
117 }
118
119 InviteCard {
120 id: inviteCard
121 invite: message.invite
122 pickerRoot: dekko
123 maxHeight: container.height / 2
124 anchors {
125 left: parent.left
126 right: parent.right
127 top: detailsPanel.bottom
128 }
129 }
130
131 DekkoWebView {
132 id: webview
133 anchors {
134 left: parent.left
135 right: parent.right
136 top: inviteCard.bottom
137 bottom: parent.bottom
138 leftMargin: !dekko.isSmallFF ? Style.smallSpacing : 0
139 }
140 }
141
142 LomiriShape {
143 // Allows to copy the currently selected text to the clipboard.
144 //
145 // Ideas for this shape taken from Morph Browser
146 // https://gitlab.com/ubports/development/core/morph-browser
147 // licensed under GPLv3
148 id: contextMenuShape
149
150 property string contextContentText: ""
151 property bool contextContentIsMail: contextContentText.startsWith("mailto:")
152
153 backgroundColor: theme.palette.normal.overlay
154 width: actionShapeRow.width + units.gu(1)
155 height: copyShape.height + units.gu(0.2) + (linkToCopyOrOpenLabel.visible ? linkToCopyOrOpenLabel.contentHeight + units.gu(0.1) : 0)
156
157 visible: false
158
159 MouseArea {
160 // to catch clicks on edges of the shape and the spacing of the Row which would
161 // otherwise go through to the underlying page as the space is not covered
162 // by the MouseAreas of the Row children
163 anchors.fill: parent
164 }
165
166 Row {
167 id: actionShapeRow
168 spacing: units.gu(3)
169
170 anchors {
171 horizontalCenter: parent.horizontalCenter
172 top: parent.top
173 topMargin: units.gu(0.1)
174 }
175
176 LomiriShape {
177 width: gripImage.width
178 height: copyShape.height // height should be as for the other shapes
179 backgroundColor: theme.palette.normal.overlay
180 aspect: LomiriShape.Flat
181 anchors.verticalCenter: parent.verticalCenter
182
183 Icon {
184 id: gripIcon
185 name: "grip-large"
186 visible: false
187 }
188
189 Image {
190 id: gripImage
191 height: parent.height
192 width: units.gu(3)
193
194 anchors {
195 top: parent.top
196 left: parent.left
197 }
198
199 source: gripIcon.source
200 fillMode: Image.PreserveAspectCrop
201 }
202
203 MouseArea {
204 anchors.fill: parent
205 drag.target: contextMenuShape
206 drag.axis: Drag.XAndYAxis
207 }
208 }
209
210 LomiriShape {
211 id: selectAllShape
212 width: (selectAllIcon.width > selectAllLabel.contentWidth ? selectAllIcon.width : selectAllLabel.contentWidth)
213 height: selectAllIcon.height + selectAllLabel.contentHeight + units.gu(1.5)
214 backgroundColor: theme.palette.normal.overlay
215 aspect: LomiriShape.Flat
216
217 Icon {
218 id: selectAllIcon
219 name: "edit-select-all"
220 height: units.gu(3)
221
222 anchors {
223 top: parent.top
224 topMargin: units.gu(0.5)
225 horizontalCenter: parent.horizontalCenter
226 }
227 }
228
229 Label {
230 id: selectAllLabel
231 anchors {
232 top: selectAllIcon.bottom
233 topMargin: units.gu(0.5)
234 horizontalCenter: parent.horizontalCenter
235 }
236 text: qsTr("Select all")
237 fontSize: "x-small"
238 }
239
240 MouseArea {
241 anchors.fill: parent
242 onClicked: {
243 webview.triggerWebAction(WebEngineView.SelectAll)
244 }
245 }
246 }
247
248 LomiriShape {
249 id: copyShape
250 width: (copyIcon.width > copyLabel.contentWidth ? copyIcon.width : copyLabel.contentWidth)
251 height: copyIcon.height + copyLabel.contentHeight + units.gu(1.5)
252 backgroundColor: theme.palette.normal.overlay
253 aspect: LomiriShape.Flat
254
255 Icon {
256 id: copyIcon
257 name: "edit-copy"
258 height: units.gu(3)
259
260 anchors {
261 top: parent.top
262 topMargin: units.gu(0.5)
263 horizontalCenter: parent.horizontalCenter
264 }
265 }
266
267 Label {
268 id: copyLabel
269 anchors {
270 top: copyIcon.bottom
271 topMargin: units.gu(0.5)
272 horizontalCenter: parent.horizontalCenter
273 }
274 text: qsTr("Copy")
275 fontSize: "x-small"
276 }
277
278 MouseArea {
279 anchors.fill: parent
280 onClicked: {
281 if (contextMenuShape.contextContentText !== "") {
282 webview.triggerWebAction(WebEngineView.CopyLinkToClipboard)
283 } else {
284 webview.triggerWebAction(WebEngineView.Copy)
285 }
286 contextMenuShape.visible = false
287 }
288 }
289 }
290
291 LomiriShape {
292 id: openUrlShape
293 width: (openUrlIcon.width > openUrlLabel.contentWidth ? openUrlIcon.width : openUrlLabel.contentWidth)
294 height: openUrlIcon.height + openUrlLabel.contentHeight + units.gu(1.5)
295 backgroundColor: theme.palette.normal.overlay
296 aspect: LomiriShape.Flat
297 visible: contextMenuShape.contextContentText !== ""
298
299 Icon {
300 id: openUrlIcon
301 name: contextMenuShape.contextContentIsMail ? "mail-unread" : "external-link"
302 height: units.gu(3)
303
304 anchors {
305 top: parent.top
306 topMargin: units.gu(0.5)
307 horizontalCenter: parent.horizontalCenter
308 }
309 }
310
311 Label {
312 id: openUrlLabel
313 anchors {
314 top: openUrlIcon.bottom
315 topMargin: units.gu(0.5)
316 horizontalCenter: parent.horizontalCenter
317 }
318 text: contextMenuShape.contextContentIsMail ? qsTr("New mail") : qsTr("Open link")
319 fontSize: "x-small"
320 }
321
322 MouseArea {
323 anchors.fill: parent
324 onClicked: {
325 Qt.openUrlExternally(contextMenuShape.contextContentText)
326 contextMenuShape.visible = false
327 }
328 }
329 }
330
331 LomiriShape {
332 width: (closeIcon.width > closeLabel.contentWidth ? closeIcon.width : closeLabel.contentWidth)
333 height: closeIcon.height + closeLabel.contentHeight + units.gu(1.5)
334 backgroundColor: theme.palette.normal.overlay
335 aspect: LomiriShape.Flat
336
337 Icon {
338 id: closeIcon
339 name: "close"
340 height: units.gu(3)
341
342 anchors {
343 top: parent.top
344 topMargin: units.gu(0.5)
345 horizontalCenter: parent.horizontalCenter
346 }
347 }
348
349 Label {
350 id: closeLabel
351 anchors {
352 top: closeIcon.bottom
353 topMargin: units.gu(0.5)
354 horizontalCenter: parent.horizontalCenter
355 }
356 text: qsTr("Close")
357 fontSize: "x-small"
358 }
359
360 MouseArea {
361 anchors.fill: parent
362 onClicked: {
363 contextMenuShape.visible = false
364 }
365 }
366 }
367 }
368
369 Label {
370 id: linkToCopyOrOpenLabel
371 text: contextMenuShape.contextContentText
372 width: parent.width - units.gu(1)
373 anchors {
374 top: actionShapeRow.bottom
375 topMargin: units.gu(0.1)
376 left: parent.left
377 leftMargin: units.gu(0.5)
378 }
379 wrapMode: Text.Wrap
380 elide: Text.ElideRight
381 maximumLineCount: 2
382 visible: text !== ""
383 }
384 }
385
387 id: h
388 msg: message
389 detailsVisible: detailsPanel.showDetails
390 width: parent.width
391 onShowDetails: detailsPanel.showDetails = !detailsPanel.showDetails
392 }
393
394 ListItem {
395 id: detailsPanel
396 property bool showDetails: false
397 property int detailsHeight: details.height > units.gu(30) ? units.gu(30) : details.height
398 color: Suru.backgroundColor
399 anchors {
400 left: parent.left
401 right: parent.right
402 top: h.bottom
403 }
404 height: 0
405 expansion.height: detailsHeight
406 expansion.expanded: showDetails
407 divider.visible: showDetails
408 Flickable {
409 anchors.fill: parent
410 contentHeight: details.height
411 Column {
412 id: details
413 anchors {
414 left: parent.left
415 leftMargin: Style.smallSpacing
416 right: parent.right
417 rightMargin: Style.smallSpacing
418 top: parent.top
419 }
420 ListItem {
421 height: units.gu(5)
422 Item {
423 id: p
424 width: tl.width + Style.smallSpacing
425 anchors {
426 left: parent.left
427 top: parent.top
428 bottom: parent.bottom
429 }
430
431 Label {
432 id: tl
433 anchors {
434 left: parent.left
435 top: parent.top
436 topMargin: Style.defaultSpacing
437 leftMargin: Style.smallSpacing
438 }
439 text: qsTr("From:")
440 }
441 }
442 LomiriShape {
443 id: delegate
444 aspect: LomiriShape.Flat
445 color: Qt.rgba(0, 0, 0, 0.05)
446 radius: "small"
447 height: units.gu(3)
448 width: inner_avatar.width + label.width + units.gu(1.5)
449 anchors {
450 left: p.right
451 leftMargin: Style.smallSpacing
452 top: parent.top
453 topMargin: units.gu(1.5)
454 }
455
456 Avatar {
457 id: inner_avatar
458 width: height
459 anchors {
460 left: parent.left
461 top: parent.top
462 bottom: parent.bottom
463 margins: units.dp(1)
464 }
465 name: message.from.name
466 initials: message.from.initials
467 email: message.from.address
468 fontSize: "x-small"
469 validContact: true
470 }
471
472 Label {
473 id: label
474 anchors {
475 left: inner_avatar.right
476 leftMargin: units.gu(0.5)
477 verticalCenter: parent.verticalCenter
478 }
479 text: message.from.name
480 }
481
482 MouseArea {
483 anchors.fill: parent
484 onClicked: {
485 PopupUtils.open(Qt.resolvedUrl("../popovers/RecipientPopover.qml"), delegate, {address: message.from})
486 }
487 }
488 }
489 }
490
492 title: qsTr("To:")
493 model: message.to
494 }
496 visible: message.cc.count
497 title: qsTr("Cc:")
498 model: message.cc
499 }
500 }
501 }
502 }
503 }
504
505 Item {
506 id: hiddenMargin
507 anchors {
508 left: parent.left
509 bottom: parent.bottom
510 right: parent.right
511 }
512 height: attachmentPanel.visible ? attachmentPanel.height : 0
513 }
514
516 id: attachmentPanel
517 attachments: message.attachments.model
518 isReadOnly: true
519 anchors {
520 left: parent.left
521 bottom: parent.bottom
522 right: parent.right
523 }
524 maxHeight: container.height - Style.defaultSpacing
525 }
526}
527