Merge lp:~boiko/messaging-app/compose_bar into lp:messaging-app
- compose_bar
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 486 |
Proposed branch: | lp:~boiko/messaging-app/compose_bar |
Merge into: | lp:messaging-app |
Prerequisite: | lp:~tiagosh/messaging-app/update-sim-dialogs |
Diff against target: |
1193 lines (+655/-449) 7 files modified
src/qml/ComposeBar.qml (+312/-0) src/qml/Messages.qml (+56/-448) src/qml/MessagesHeader.qml (+1/-1) src/qml/ThumbnailContact.qml (+106/-0) src/qml/ThumbnailImage.qml (+49/-0) src/qml/ThumbnailUnknown.qml (+45/-0) src/qml/TransparentButton.qml (+86/-0) |
To merge this branch: | bzr merge lp:~boiko/messaging-app/compose_bar |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot | continuous-integration | Needs Fixing | |
Tiago Salem Herrmann (community) | Needs Fixing | ||
Review via email: mp+278208@code.launchpad.net |
Commit message
Move the bottom part of Messages view to a separate QML file for better code readability.
Description of the change
Move the bottom part of Messages view to a separate QML file for better code readability.
PS Jenkins bot (ps-jenkins) wrote : | # |
- 444. By Gustavo Pichorim Boiko
-
Merge latest changes from trunk.
- 445. By Gustavo Pichorim Boiko
-
Remove unused include.
- 446. By Gustavo Pichorim Boiko
-
Add missing thumbnail files.
- 447. By Gustavo Pichorim Boiko
-
Merge latest changes from trunk.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:445
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:447
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 448. By Gustavo Pichorim Boiko
-
Merge latest changes from trunk.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:448
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
Tiago Salem Herrmann (tiagosh) : | # |
- 449. By Gustavo Pichorim Boiko
-
Fix import version.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:449
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 450. By Gustavo Pichorim Boiko
-
Add missing copyright.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:450
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Tiago Salem Herrmann (tiagosh) : | # |
- 451. By Gustavo Pichorim Boiko
-
Add missing pressAndHold() signal and make use of it
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:451
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 452. By Gustavo Pichorim Boiko
-
Merge trunk.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:452
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 453. By Gustavo Pichorim Boiko
-
Merge trunk.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:453
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
UNSTABLE: http://
SUCCESS: http://
deb: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Preview Diff
1 | === added file 'src/qml/ComposeBar.qml' |
2 | --- src/qml/ComposeBar.qml 1970-01-01 00:00:00 +0000 |
3 | +++ src/qml/ComposeBar.qml 2015-12-08 17:14:16 +0000 |
4 | @@ -0,0 +1,312 @@ |
5 | +/* |
6 | + * Copyright 2012-2015 Canonical Ltd. |
7 | + * |
8 | + * This file is part of messaging-app. |
9 | + * |
10 | + * messaging-app is free software; you can redistribute it and/or modify |
11 | + * it under the terms of the GNU General Public License as published by |
12 | + * the Free Software Foundation; version 3. |
13 | + * |
14 | + * messaging-app is distributed in the hope that it will be useful, |
15 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | + * GNU General Public License for more details. |
18 | + * |
19 | + * You should have received a copy of the GNU General Public License |
20 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
21 | + */ |
22 | + |
23 | +import QtQuick 2.0 |
24 | +import Ubuntu.Components 1.3 |
25 | +import Ubuntu.Components.ListItems 1.3 as ListItem |
26 | +import Ubuntu.Components.Popups 1.3 |
27 | +import Ubuntu.Content 0.1 |
28 | +import Ubuntu.Telephony 0.1 |
29 | + |
30 | +Item { |
31 | + id: composeBar |
32 | + |
33 | + property bool showContents: true |
34 | + property int maxHeight: textEntry.height + units.gu(2) |
35 | + property variant attachments: [] |
36 | + property bool canSend: true |
37 | + property alias text: messageTextArea.text |
38 | + |
39 | + signal sendRequested(string text, var attachments) |
40 | + |
41 | + // internal properties |
42 | + property int _activeAttachmentIndex: -1 |
43 | + property int _defaultHeight: textEntry.height + units.gu(2) |
44 | + |
45 | + function forceFocus() { |
46 | + messageTextArea.forceActiveFocus() |
47 | + } |
48 | + |
49 | + function reset() { |
50 | + textEntry.text = "" |
51 | + attachments.clear() |
52 | + } |
53 | + |
54 | + function addAttachments(transfer) { |
55 | + for (var i = 0; i < transfer.items.length; i++) { |
56 | + if (String(transfer.items[i].text).length > 0) { |
57 | + composeBar.text = String(transfer.items[i].text) |
58 | + continue |
59 | + } |
60 | + var attachment = {} |
61 | + if (!startsWith(String(transfer.items[i].url),"file://")) { |
62 | + composeBar.text = String(transfer.items[i].url) |
63 | + continue |
64 | + } |
65 | + var filePath = String(transfer.items[i].url).replace('file://', '') |
66 | + // get only the basename |
67 | + attachment["contentType"] = application.fileMimeType(filePath) |
68 | + if (startsWith(attachment["contentType"], "text/vcard") || |
69 | + startsWith(attachment["contentType"], "text/x-vcard")) { |
70 | + attachment["name"] = "contact.vcf" |
71 | + } else { |
72 | + attachment["name"] = filePath.split('/').reverse()[0] |
73 | + } |
74 | + attachment["filePath"] = filePath |
75 | + attachments.append(attachment) |
76 | + } |
77 | + } |
78 | + |
79 | + function formattedTime(time) { |
80 | + var d = new Date(0, 0, 0, 0, 0, time) |
81 | + return d.getHours() == 0 ? Qt.formatTime(d, "mm:ss") : Qt.formatTime(d, "h:mm:ss") |
82 | + } |
83 | + |
84 | + anchors.bottom: isSearching ? parent.bottom : keyboard.top |
85 | + anchors.left: parent.left |
86 | + anchors.right: parent.right |
87 | + height: showContents ? Math.min(_defaultHeight, maxHeight) : 0 |
88 | + visible: showContents |
89 | + clip: true |
90 | + |
91 | + Behavior on height { |
92 | + UbuntuNumberAnimation { } |
93 | + } |
94 | + |
95 | + MouseArea { |
96 | + anchors.fill: parent |
97 | + onClicked: { |
98 | + forceFocus() |
99 | + } |
100 | + } |
101 | + |
102 | + ListModel { |
103 | + id: attachments |
104 | + } |
105 | + |
106 | + Component { |
107 | + id: attachmentPopover |
108 | + |
109 | + Popover { |
110 | + id: popover |
111 | + Column { |
112 | + id: containerLayout |
113 | + anchors { |
114 | + left: parent.left |
115 | + top: parent.top |
116 | + right: parent.right |
117 | + } |
118 | + ListItem.Standard { |
119 | + text: i18n.tr("Remove") |
120 | + onClicked: { |
121 | + attachments.remove(_activeAttachmentIndex) |
122 | + PopupUtils.close(popover) |
123 | + } |
124 | + } |
125 | + } |
126 | + Component.onDestruction: _activeAttachmentIndex = -1 |
127 | + } |
128 | + } |
129 | + |
130 | + ListItem.ThinDivider { |
131 | + anchors.top: parent.top |
132 | + } |
133 | + |
134 | + Row { |
135 | + id: leftSideActions |
136 | + |
137 | + width: childrenRect.width |
138 | + height: childrenRect.height |
139 | + |
140 | + anchors { |
141 | + left: parent.left |
142 | + leftMargin: units.gu(2) |
143 | + verticalCenter: sendButton.verticalCenter |
144 | + } |
145 | + spacing: units.gu(2) |
146 | + |
147 | + PictureImport { |
148 | + id: pictureImporter |
149 | + |
150 | + onPictureReceived: { |
151 | + var attachment = {} |
152 | + var filePath = String(pictureUrl).replace('file://', '') |
153 | + attachment["contentType"] = application.fileMimeType(filePath) |
154 | + attachment["name"] = filePath.split('/').reverse()[0] |
155 | + attachment["filePath"] = filePath |
156 | + attachments.append(attachment) |
157 | + textEntry.forceActiveFocus() |
158 | + } |
159 | + } |
160 | + |
161 | + TransparentButton { |
162 | + id: attachButton |
163 | + objectName: "attachButton" |
164 | + iconName: "camera-app-symbolic" |
165 | + onClicked: { |
166 | + Qt.inputMethod.hide() |
167 | + pictureImporter.requestNewPicture() |
168 | + } |
169 | + } |
170 | + } |
171 | + |
172 | + StyledItem { |
173 | + id: textEntry |
174 | + property alias text: messageTextArea.text |
175 | + property alias inputMethodComposing: messageTextArea.inputMethodComposing |
176 | + property int fullSize: attachmentThumbnails.height + messageTextArea.height |
177 | + style: Theme.createStyleComponent("TextAreaStyle.qml", textEntry) |
178 | + anchors { |
179 | + topMargin: units.gu(1) |
180 | + top: parent.top |
181 | + left: leftSideActions.right |
182 | + leftMargin: units.gu(2) |
183 | + right: sendButton.left |
184 | + rightMargin: units.gu(2) |
185 | + } |
186 | + height: attachments.count !== 0 ? fullSize + units.gu(1.5) : fullSize |
187 | + onActiveFocusChanged: { |
188 | + if(activeFocus) { |
189 | + messageTextArea.forceActiveFocus() |
190 | + } else { |
191 | + focus = false |
192 | + } |
193 | + } |
194 | + focus: false |
195 | + MouseArea { |
196 | + anchors.fill: parent |
197 | + onClicked: forceFocus() |
198 | + } |
199 | + Flow { |
200 | + id: attachmentThumbnails |
201 | + spacing: units.gu(1) |
202 | + anchors{ |
203 | + left: parent.left |
204 | + right: parent.right |
205 | + top: parent.top |
206 | + topMargin: units.gu(1) |
207 | + leftMargin: units.gu(1) |
208 | + rightMargin: units.gu(1) |
209 | + } |
210 | + height: childrenRect.height |
211 | + |
212 | + Repeater { |
213 | + model: attachments |
214 | + delegate: Loader { |
215 | + id: loader |
216 | + height: units.gu(8) |
217 | + source: { |
218 | + var contentType = getContentType(filePath) |
219 | + console.log(contentType) |
220 | + switch(contentType) { |
221 | + case ContentType.Contacts: |
222 | + return Qt.resolvedUrl("ThumbnailContact.qml") |
223 | + case ContentType.Pictures: |
224 | + return Qt.resolvedUrl("ThumbnailImage.qml") |
225 | + case ContentType.Unknown: |
226 | + return Qt.resolvedUrl("ThumbnailUnknown.qml") |
227 | + default: |
228 | + console.log("unknown content Type") |
229 | + } |
230 | + } |
231 | + onStatusChanged: { |
232 | + if (status == Loader.Ready) { |
233 | + item.index = index |
234 | + item.filePath = filePath |
235 | + } |
236 | + } |
237 | + |
238 | + Connections { |
239 | + target: loader.status == Loader.Ready ? loader.item : null |
240 | + ignoreUnknownSignals: true |
241 | + onPressAndHold: { |
242 | + Qt.inputMethod.hide() |
243 | + _activeAttachmentIndex = target.index |
244 | + PopupUtils.open(attachmentPopover, parent) |
245 | + } |
246 | + } |
247 | + } |
248 | + } |
249 | + } |
250 | + |
251 | + ListItem.ThinDivider { |
252 | + id: divider |
253 | + |
254 | + anchors { |
255 | + left: parent.left |
256 | + right: parent.right |
257 | + top: attachmentThumbnails.bottom |
258 | + margins: units.gu(0.5) |
259 | + } |
260 | + visible: attachments.count > 0 |
261 | + } |
262 | + |
263 | + TextArea { |
264 | + id: messageTextArea |
265 | + objectName: "messageTextArea" |
266 | + anchors { |
267 | + top: attachments.count == 0 ? textEntry.top : attachmentThumbnails.bottom |
268 | + left: parent.left |
269 | + right: parent.right |
270 | + } |
271 | + // this value is to avoid letter being cut off |
272 | + height: units.gu(4.3) |
273 | + style: LocalTextAreaStyle {} |
274 | + autoSize: true |
275 | + maximumLineCount: attachments.count == 0 ? 8 : 4 |
276 | + placeholderText: { |
277 | + if (telepathyHelper.ready) { |
278 | + var account = telepathyHelper.accountForId(presenceRequest.accountId) |
279 | + if (account && |
280 | + (presenceRequest.type != PresenceRequest.PresenceTypeUnknown && |
281 | + presenceRequest.type != PresenceRequest.PresenceTypeUnset) && |
282 | + account.protocolInfo.serviceName !== "") { |
283 | + console.log(presenceRequest.accountId) |
284 | + console.log(presenceRequest.type) |
285 | + return account.protocolInfo.serviceName |
286 | + } |
287 | + } |
288 | + return i18n.tr("Write a message...") |
289 | + } |
290 | + focus: textEntry.focus |
291 | + font.family: "Ubuntu" |
292 | + font.pixelSize: FontUtils.sizeToPixels("medium") |
293 | + color: "#5d5d5d" |
294 | + } |
295 | + } |
296 | + |
297 | + TransparentButton { |
298 | + id: sendButton |
299 | + objectName: "sendButton" |
300 | + anchors.verticalCenter: textEntry.verticalCenter |
301 | + anchors.right: parent.right |
302 | + anchors.rightMargin: units.gu(2) |
303 | + iconSource: Qt.resolvedUrl("./assets/send.svg") |
304 | + enabled: (canSend && (textEntry.text != "" || textEntry.inputMethodComposing || attachments.count > 0)) |
305 | + |
306 | + onClicked: { |
307 | + // make sure we flush everything we have prepared in the OSK preedit |
308 | + Qt.inputMethod.commit(); |
309 | + if (textEntry.text == "" && attachments.count == 0) { |
310 | + return |
311 | + } |
312 | + |
313 | + composeBar.sendRequested(textEntry.text, attachments) |
314 | + } |
315 | + } |
316 | +} |
317 | |
318 | === modified file 'src/qml/Messages.qml' |
319 | --- src/qml/Messages.qml 2015-12-07 17:55:17 +0000 |
320 | +++ src/qml/Messages.qml 2015-12-08 17:14:16 +0000 |
321 | @@ -1,5 +1,5 @@ |
322 | /* |
323 | - * Copyright 2012, 2013, 2014 Canonical Ltd. |
324 | + * Copyright 2012-2015 Canonical Ltd. |
325 | * |
326 | * This file is part of messaging-app. |
327 | * |
328 | @@ -272,32 +272,6 @@ |
329 | sections.selectedIndex: getSelectedIndex() |
330 | } |
331 | |
332 | - |
333 | - function addAttachmentsToModel(transfer) { |
334 | - for (var i in transfer.items) { |
335 | - if (String(transfer.items[i].text).length > 0) { |
336 | - messages.text = String(transfer.items[i].text) |
337 | - continue |
338 | - } |
339 | - var attachment = {} |
340 | - if (!startsWith(String(transfer.items[i].url),"file://")) { |
341 | - messages.text = String(transfer.items[i].url) |
342 | - continue |
343 | - } |
344 | - var filePath = String(transfer.items[i].url).replace('file://', '') |
345 | - // get only the basename |
346 | - attachment["contentType"] = application.fileMimeType(filePath) |
347 | - if (startsWith(attachment["contentType"], "text/vcard") || |
348 | - startsWith(attachment["contentType"], "text/x-vcard")) { |
349 | - attachment["name"] = "contact.vcf" |
350 | - } else { |
351 | - attachment["name"] = filePath.split('/').reverse()[0] |
352 | - } |
353 | - attachment["filePath"] = filePath |
354 | - attachments.append(attachment) |
355 | - } |
356 | - } |
357 | - |
358 | function sendMessageNetworkCheck() { |
359 | if (messages.account.simLocked) { |
360 | Qt.inputMethod.hide() |
361 | @@ -500,24 +474,6 @@ |
362 | visible: running |
363 | } |
364 | |
365 | - ListModel { |
366 | - id: attachments |
367 | - } |
368 | - |
369 | - PictureImport { |
370 | - id: pictureImporter |
371 | - |
372 | - onPictureReceived: { |
373 | - var attachment = {} |
374 | - var filePath = String(pictureUrl).replace('file://', '') |
375 | - attachment["contentType"] = application.fileMimeType(filePath) |
376 | - attachment["name"] = filePath.split('/').reverse()[0] |
377 | - attachment["filePath"] = filePath |
378 | - attachments.append(attachment) |
379 | - textEntry.forceActiveFocus() |
380 | - } |
381 | - } |
382 | - |
383 | flickable: null |
384 | |
385 | property bool isReady: false |
386 | @@ -560,7 +516,7 @@ |
387 | } |
388 | } |
389 | } |
390 | - addAttachmentsToModel(sharedAttachmentsTransfer) |
391 | + composeBar.addAttachments(sharedAttachmentsTransfer) |
392 | } |
393 | |
394 | onActiveChanged: { |
395 | @@ -642,30 +598,6 @@ |
396 | } |
397 | |
398 | Component { |
399 | - id: attachmentPopover |
400 | - |
401 | - Popover { |
402 | - id: popover |
403 | - Column { |
404 | - id: containerLayout |
405 | - anchors { |
406 | - left: parent.left |
407 | - top: parent.top |
408 | - right: parent.right |
409 | - } |
410 | - ListItem.Standard { |
411 | - text: i18n.tr("Remove") |
412 | - onClicked: { |
413 | - attachments.remove(activeAttachmentIndex) |
414 | - PopupUtils.close(popover) |
415 | - } |
416 | - } |
417 | - } |
418 | - Component.onDestruction: activeAttachmentIndex = -1 |
419 | - } |
420 | - } |
421 | - |
422 | - Component { |
423 | id: participantsPopover |
424 | |
425 | Popover { |
426 | @@ -748,7 +680,7 @@ |
427 | topMargin: units.gu(2) |
428 | left: parent.left |
429 | right: parent.right |
430 | - bottom: bottomPanel.top |
431 | + bottom: composeBar.top |
432 | } |
433 | z: 1 |
434 | Behavior on height { |
435 | @@ -1029,386 +961,62 @@ |
436 | top: screenTop.bottom |
437 | left: parent.left |
438 | right: parent.right |
439 | - bottom: bottomPanel.top |
440 | + bottom: composeBar.top |
441 | } |
442 | } |
443 | |
444 | - Item { |
445 | - id: bottomPanel |
446 | - property int defaultHeight: textEntry.height + units.gu(2) |
447 | - anchors.bottom: isSearching ? parent.bottom : keyboard.top |
448 | - anchors.left: parent.left |
449 | - anchors.right: parent.right |
450 | - height: { |
451 | - if (selectionMode || (participants.length > 0 && !contactWatcher.interactive)) { |
452 | - return 0 |
453 | - } else { |
454 | - if (messages.height - keyboard.height - screenTop.y > defaultHeight) { |
455 | - return defaultHeight |
456 | - } else { |
457 | - return messages.height - keyboard.height - screenTop.y |
458 | - } |
459 | - } |
460 | - } |
461 | - visible: !selectionMode && !isSearching |
462 | - clip: true |
463 | - MouseArea { |
464 | - anchors.fill: parent |
465 | - onClicked: { |
466 | - messageTextArea.forceActiveFocus() |
467 | - } |
468 | - } |
469 | - |
470 | - Behavior on height { |
471 | - UbuntuNumberAnimation { } |
472 | - } |
473 | - |
474 | - ListItem.ThinDivider { |
475 | - anchors.top: parent.top |
476 | - } |
477 | - |
478 | - Icon { |
479 | - id: attachButton |
480 | - objectName: "attachButton" |
481 | - anchors.left: parent.left |
482 | - anchors.leftMargin: units.gu(2) |
483 | - anchors.verticalCenter: sendButton.verticalCenter |
484 | - height: units.gu(3) |
485 | - width: units.gu(3) |
486 | - color: "gray" |
487 | - name: "camera-app-symbolic" |
488 | - MouseArea { |
489 | - anchors.fill: parent |
490 | - anchors.margins: units.gu(-2) |
491 | - onClicked: { |
492 | - Qt.inputMethod.hide() |
493 | - pictureImporter.requestNewPicture() |
494 | - } |
495 | - } |
496 | - } |
497 | - |
498 | - StyledItem { |
499 | - id: textEntry |
500 | - property alias text: messageTextArea.text |
501 | - property alias inputMethodComposing: messageTextArea.inputMethodComposing |
502 | - property int fullSize: attachmentThumbnails.height + messageTextArea.height |
503 | - style: Theme.createStyleComponent("TextAreaStyle.qml", textEntry) |
504 | - anchors.bottomMargin: units.gu(1) |
505 | - anchors.bottom: parent.bottom |
506 | - anchors.left: attachButton.right |
507 | - anchors.leftMargin: units.gu(1) |
508 | - anchors.right: sendButton.left |
509 | - anchors.rightMargin: units.gu(1) |
510 | - height: attachments.count !== 0 ? fullSize + units.gu(1.5) : fullSize |
511 | - onActiveFocusChanged: { |
512 | - if(activeFocus) { |
513 | - messageTextArea.forceActiveFocus() |
514 | - } else { |
515 | - focus = false |
516 | - } |
517 | - } |
518 | - focus: false |
519 | - MouseArea { |
520 | - anchors.fill: parent |
521 | - onClicked: messageTextArea.forceActiveFocus() |
522 | - } |
523 | - Flow { |
524 | - id: attachmentThumbnails |
525 | - spacing: units.gu(1) |
526 | - anchors{ |
527 | - left: parent.left |
528 | - right: parent.right |
529 | - top: parent.top |
530 | - topMargin: units.gu(1) |
531 | - leftMargin: units.gu(1) |
532 | - rightMargin: units.gu(1) |
533 | - } |
534 | - height: childrenRect.height |
535 | - |
536 | - Component { |
537 | - id: thumbnailImage |
538 | - UbuntuShape { |
539 | - property int index |
540 | - property string filePath |
541 | - |
542 | - width: childrenRect.width |
543 | - height: childrenRect.height |
544 | - |
545 | - image: Image { |
546 | - id: avatarImage |
547 | - width: units.gu(8) |
548 | - height: units.gu(8) |
549 | - sourceSize.height: height |
550 | - sourceSize.width: width |
551 | - fillMode: Image.PreserveAspectCrop |
552 | - source: filePath |
553 | - asynchronous: true |
554 | - } |
555 | - MouseArea { |
556 | - anchors.fill: parent |
557 | - onPressAndHold: { |
558 | - mouse.accept = true |
559 | - Qt.inputMethod.hide() |
560 | - activeAttachmentIndex = index |
561 | - PopupUtils.open(attachmentPopover, parent) |
562 | - } |
563 | - } |
564 | - } |
565 | - } |
566 | - |
567 | - Component { |
568 | - id: thumbnailContact |
569 | - Item { |
570 | - id: attachment |
571 | - |
572 | - readonly property int contactsCount:vcardParser.contacts ? vcardParser.contacts.length : 0 |
573 | - property int index |
574 | - property string filePath |
575 | - property alias vcard: vcardParser |
576 | - property string contactDisplayName: { |
577 | - if (contactsCount > 0) { |
578 | - var contact = vcard.contacts[0] |
579 | - if (contact.displayLabel.label && (contact.displayLabel.label != "")) { |
580 | - return contact.displayLabel.label |
581 | - } else if (contact.name) { |
582 | - var contacFullName = contact.name.firstName |
583 | - if (contact.name.midleName) { |
584 | - contacFullName += " " + contact.name.midleName |
585 | - } |
586 | - if (contact.name.lastName) { |
587 | - contacFullName += " " + contact.name.lastName |
588 | - } |
589 | - return contacFullName |
590 | - } |
591 | - return i18n.tr("Unknown contact") |
592 | - } |
593 | - return "" |
594 | - } |
595 | - property string title: { |
596 | - var result = attachment.contactDisplayName |
597 | - if (attachment.contactsCount > 1) { |
598 | - return result + " (+%1)".arg(attachment.contactsCount-1) |
599 | - } else { |
600 | - return result |
601 | - } |
602 | - } |
603 | - |
604 | - height: units.gu(6) |
605 | - width: textEntry.width |
606 | - |
607 | - ContactAvatar { |
608 | - id: avatar |
609 | - |
610 | - anchors { |
611 | - top: parent.top |
612 | - bottom: parent.bottom |
613 | - left: parent.left |
614 | - } |
615 | - contactElement: attachment.contactsCount === 1 ? attachment.vcard.contacts[0] : null |
616 | - fallbackAvatarUrl: attachment.contactsCount === 1 ? "image://theme/contact" : "image://theme/contact-group" |
617 | - fallbackDisplayName: attachment.contactsCount === 1 ? attachment.contactDisplayName : "" |
618 | - width: height |
619 | - } |
620 | - Label { |
621 | - id: label |
622 | - |
623 | - anchors { |
624 | - left: avatar.right |
625 | - leftMargin: units.gu(1) |
626 | - top: avatar.top |
627 | - bottom: avatar.bottom |
628 | - right: parent.right |
629 | - rightMargin: units.gu(1) |
630 | - } |
631 | - |
632 | - verticalAlignment: Text.AlignVCenter |
633 | - text: attachment.title |
634 | - elide: Text.ElideMiddle |
635 | - color: UbuntuColors.lightAubergine |
636 | - } |
637 | - MouseArea { |
638 | - anchors.fill: parent |
639 | - onPressAndHold: { |
640 | - mouse.accept = true |
641 | - Qt.inputMethod.hide() |
642 | - activeAttachmentIndex = index |
643 | - PopupUtils.open(attachmentPopover, parent) |
644 | - } |
645 | - } |
646 | - VCardParser { |
647 | - id: vcardParser |
648 | - |
649 | - vCardUrl: attachment ? Qt.resolvedUrl(attachment.filePath) : "" |
650 | - } |
651 | - } |
652 | - } |
653 | - |
654 | - Component { |
655 | - id: thumbnailUnknown |
656 | - |
657 | - UbuntuShape { |
658 | - property int index |
659 | - property string filePath |
660 | - |
661 | - width: units.gu(8) |
662 | - height: units.gu(8) |
663 | - |
664 | - Icon { |
665 | - anchors.centerIn: parent |
666 | - width: units.gu(6) |
667 | - height: units.gu(6) |
668 | - name: "attachment" |
669 | - } |
670 | - MouseArea { |
671 | - anchors.fill: parent |
672 | - onPressAndHold: { |
673 | - mouse.accept = true |
674 | - Qt.inputMethod.hide() |
675 | - activeAttachmentIndex = index |
676 | - PopupUtils.open(attachmentPopover, parent) |
677 | - } |
678 | - } |
679 | - } |
680 | - } |
681 | - |
682 | - Repeater { |
683 | - model: attachments |
684 | - delegate: Loader { |
685 | - height: units.gu(8) |
686 | - sourceComponent: { |
687 | - var contentType = getContentType(filePath) |
688 | - console.log(contentType) |
689 | - switch(contentType) { |
690 | - case ContentType.Contacts: |
691 | - return thumbnailContact |
692 | - case ContentType.Pictures: |
693 | - return thumbnailImage |
694 | - case ContentType.Unknown: |
695 | - return thumbnailUnknown |
696 | - default: |
697 | - console.log("unknown content Type") |
698 | - } |
699 | - } |
700 | - onStatusChanged: { |
701 | - if (status == Loader.Ready) { |
702 | - item.index = index |
703 | - item.filePath = filePath |
704 | - } |
705 | - } |
706 | - } |
707 | - } |
708 | - } |
709 | - |
710 | - ListItem.ThinDivider { |
711 | - id: divider |
712 | - |
713 | - anchors { |
714 | - left: parent.left |
715 | - right: parent.right |
716 | - top: attachmentThumbnails.bottom |
717 | - margins: units.gu(0.5) |
718 | - } |
719 | - visible: attachments.count > 0 |
720 | - } |
721 | - |
722 | - TextArea { |
723 | - id: messageTextArea |
724 | - objectName: "messageTextArea" |
725 | - anchors { |
726 | - top: attachments.count == 0 ? textEntry.top : attachmentThumbnails.bottom |
727 | - left: parent.left |
728 | - right: parent.right |
729 | - } |
730 | - // this value is to avoid letter being cut off |
731 | - height: units.gu(4.3) |
732 | - style: LocalTextAreaStyle {} |
733 | - autoSize: true |
734 | - maximumLineCount: attachments.count == 0 ? 8 : 4 |
735 | - placeholderText: i18n.tr("Write a message...") |
736 | - focus: textEntry.focus |
737 | - font.family: "Ubuntu" |
738 | - font.pixelSize: FontUtils.sizeToPixels("medium") |
739 | - color: "#5d5d5d" |
740 | - text: messages.text |
741 | - } |
742 | - |
743 | - /*InverseMouseArea { |
744 | - anchors.fill: parent |
745 | - visible: textEntry.activeFocus |
746 | - onClicked: { |
747 | - textEntry.focus = false; |
748 | - } |
749 | - }*/ |
750 | - Component.onCompleted: { |
751 | - // if page is active, it means this is not a bottom edge page |
752 | - if (messages.active && messages.keyboardFocus && participants.length != 0) { |
753 | - messageTextArea.forceActiveFocus() |
754 | - } |
755 | - } |
756 | - } |
757 | - |
758 | - Icon { |
759 | - id: sendButton |
760 | - objectName: "sendButton" |
761 | - anchors.verticalCenter: textEntry.verticalCenter |
762 | - anchors.right: parent.right |
763 | - anchors.rightMargin: units.gu(2) |
764 | - color: "gray" |
765 | - source: Qt.resolvedUrl("./assets/send.svg") |
766 | - width: units.gu(3) |
767 | - height: units.gu(3) |
768 | - enabled: { |
769 | - if (participants.length > 0 || multiRecipient.recipientCount > 0 || multiRecipient.searchString !== "") { |
770 | - if (textEntry.text != "" || textEntry.inputMethodComposing || attachments.count > 0) { |
771 | - return true |
772 | - } |
773 | - } |
774 | - return false |
775 | - } |
776 | - |
777 | - MouseArea { |
778 | - anchors.fill: parent |
779 | - anchors.margins: units.gu(-2) |
780 | - onClicked: { |
781 | - // make sure we flush everything we have prepared in the OSK preedit |
782 | - Qt.inputMethod.commit(); |
783 | - if (textEntry.text == "" && attachments.count == 0) { |
784 | - return |
785 | - } |
786 | - // refresh the recipient list |
787 | - multiRecipient.focus = false |
788 | - |
789 | - if (messages.account && messages.accountId == "") { |
790 | - messages.accountId = messages.account.accountId |
791 | - messages.head.sections.selectedIndex = Qt.binding(getSelectedIndex) |
792 | - } |
793 | - |
794 | - var newAttachments = [] |
795 | - for (var i = 0; i < attachments.count; i++) { |
796 | - var attachment = [] |
797 | - var item = attachments.get(i) |
798 | - // we dont include smil files. they will be auto generated |
799 | - if (item.contentType.toLowerCase() === "application/smil") { |
800 | - continue |
801 | - } |
802 | - attachment.push(item.name) |
803 | - attachment.push(item.contentType) |
804 | - attachment.push(item.filePath) |
805 | - newAttachments.push(attachment) |
806 | - } |
807 | - |
808 | - var recipients = participantIds.length > 0 ? participantIds : |
809 | - multiRecipient.recipients |
810 | - // if sendMessage succeeds it means the message was either sent or |
811 | - // injected into the history service so the user can retry later |
812 | - if (sendMessage(textEntry.text, recipients, newAttachments)) { |
813 | - textEntry.text = "" |
814 | - attachments.clear() |
815 | - } |
816 | - if (eventModel.filter == null) { |
817 | - reloadFilters = !reloadFilters |
818 | - } |
819 | - } |
820 | + ComposeBar { |
821 | + id: composeBar |
822 | + anchors { |
823 | + bottom: isSearching ? parent.bottom : keyboard.top |
824 | + left: parent.left |
825 | + right: parent.right |
826 | + } |
827 | + |
828 | + showContents: !selectionMode && !isSearching |
829 | + maxHeight: messages.height - keyboard.height - screenTop.y |
830 | + text: messages.text |
831 | + canSend: participants.length > 0 || multiRecipient.recipientCount > 0 || multiRecipient.searchString !== "" |
832 | + |
833 | + Component.onCompleted: { |
834 | + // if page is active, it means this is not a bottom edge page |
835 | + if (messages.active && messages.keyboardFocus && participants.length != 0) { |
836 | + forceFocus() |
837 | + } |
838 | + } |
839 | + |
840 | + onSendRequested: { |
841 | + // refresh the recipient list |
842 | + multiRecipient.focus = false |
843 | + |
844 | + if (messages.account && messages.accountId == "") { |
845 | + messages.accountId = messages.account.accountId |
846 | + messages.head.sections.selectedIndex = Qt.binding(getSelectedIndex) |
847 | + } |
848 | + |
849 | + var newAttachments = [] |
850 | + for (var i = 0; i < attachments.count; i++) { |
851 | + var attachment = [] |
852 | + var item = attachments.get(i) |
853 | + // we dont include smil files. they will be auto generated |
854 | + if (item.contentType.toLowerCase() === "application/smil") { |
855 | + continue |
856 | + } |
857 | + attachment.push(item.name) |
858 | + attachment.push(item.contentType) |
859 | + attachment.push(item.filePath) |
860 | + newAttachments.push(attachment) |
861 | + } |
862 | + |
863 | + var recipients = participantIds.length > 0 ? participantIds : |
864 | + multiRecipient.recipients |
865 | + // if sendMessage succeeds it means the message was either sent or |
866 | + // injected into the history service so the user can retry later |
867 | + if (sendMessage(text, recipients, newAttachments)) { |
868 | + composeBar.reset() |
869 | + } |
870 | + if (eventModel.filter == null) { |
871 | + reloadFilters = !reloadFilters |
872 | } |
873 | } |
874 | } |
875 | |
876 | === modified file 'src/qml/MessagesHeader.qml' |
877 | --- src/qml/MessagesHeader.qml 2015-08-04 01:06:06 +0000 |
878 | +++ src/qml/MessagesHeader.qml 2015-12-08 17:14:16 +0000 |
879 | @@ -18,7 +18,7 @@ |
880 | |
881 | |
882 | import QtQuick 2.2 |
883 | -import Ubuntu.Components 1.1 |
884 | +import Ubuntu.Components 1.3 |
885 | |
886 | Item { |
887 | id: header |
888 | |
889 | === added file 'src/qml/ThumbnailContact.qml' |
890 | --- src/qml/ThumbnailContact.qml 1970-01-01 00:00:00 +0000 |
891 | +++ src/qml/ThumbnailContact.qml 2015-12-08 17:14:16 +0000 |
892 | @@ -0,0 +1,106 @@ |
893 | +/* |
894 | + * Copyright 2012-2015 Canonical Ltd. |
895 | + * |
896 | + * This file is part of messaging-app. |
897 | + * |
898 | + * messaging-app is free software; you can redistribute it and/or modify |
899 | + * it under the terms of the GNU General Public License as published by |
900 | + * the Free Software Foundation; version 3. |
901 | + * |
902 | + * messaging-app is distributed in the hope that it will be useful, |
903 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
904 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
905 | + * GNU General Public License for more details. |
906 | + * |
907 | + * You should have received a copy of the GNU General Public License |
908 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
909 | + */ |
910 | + |
911 | +import QtQuick 2.0 |
912 | +import Ubuntu.Components 1.3 |
913 | +import Ubuntu.Contacts 0.1 |
914 | + |
915 | +Item { |
916 | + id: attachment |
917 | + |
918 | + readonly property int contactsCount:vcardParser.contacts ? vcardParser.contacts.length : 0 |
919 | + property int index |
920 | + property string filePath |
921 | + property alias vcard: vcardParser |
922 | + property string contactDisplayName: { |
923 | + if (contactsCount > 0) { |
924 | + var contact = vcard.contacts[0] |
925 | + if (contact.displayLabel.label && (contact.displayLabel.label != "")) { |
926 | + return contact.displayLabel.label |
927 | + } else if (contact.name) { |
928 | + var contacFullName = contact.name.firstName |
929 | + if (contact.name.midleName) { |
930 | + contacFullName += " " + contact.name.midleName |
931 | + } |
932 | + if (contact.name.lastName) { |
933 | + contacFullName += " " + contact.name.lastName |
934 | + } |
935 | + return contacFullName |
936 | + } |
937 | + return i18n.tr("Unknown contact") |
938 | + } |
939 | + return "" |
940 | + } |
941 | + property string title: { |
942 | + var result = attachment.contactDisplayName |
943 | + if (attachment.contactsCount > 1) { |
944 | + return result + " (+%1)".arg(attachment.contactsCount-1) |
945 | + } else { |
946 | + return result |
947 | + } |
948 | + } |
949 | + |
950 | + signal pressAndHold() |
951 | + |
952 | + height: units.gu(6) |
953 | + width: textEntry.width |
954 | + |
955 | + ContactAvatar { |
956 | + id: avatar |
957 | + |
958 | + anchors { |
959 | + top: parent.top |
960 | + bottom: parent.bottom |
961 | + left: parent.left |
962 | + } |
963 | + contactElement: attachment.contactsCount === 1 ? attachment.vcard.contacts[0] : null |
964 | + fallbackAvatarUrl: attachment.contactsCount === 1 ? "image://theme/contact" : "image://theme/contact-group" |
965 | + fallbackDisplayName: attachment.contactsCount === 1 ? attachment.contactDisplayName : "" |
966 | + width: height |
967 | + } |
968 | + Label { |
969 | + id: label |
970 | + |
971 | + anchors { |
972 | + left: avatar.right |
973 | + leftMargin: units.gu(1) |
974 | + top: avatar.top |
975 | + bottom: avatar.bottom |
976 | + right: parent.right |
977 | + rightMargin: units.gu(1) |
978 | + } |
979 | + |
980 | + verticalAlignment: Text.AlignVCenter |
981 | + text: attachment.title |
982 | + elide: Text.ElideMiddle |
983 | + color: UbuntuColors.lightAubergine |
984 | + } |
985 | + MouseArea { |
986 | + anchors.fill: parent |
987 | + onPressAndHold: { |
988 | + mouse.accept = true |
989 | + attachment.pressAndHold() |
990 | + } |
991 | + } |
992 | + VCardParser { |
993 | + id: vcardParser |
994 | + |
995 | + vCardUrl: attachment ? Qt.resolvedUrl(attachment.filePath) : "" |
996 | + } |
997 | +} |
998 | + |
999 | |
1000 | === added file 'src/qml/ThumbnailImage.qml' |
1001 | --- src/qml/ThumbnailImage.qml 1970-01-01 00:00:00 +0000 |
1002 | +++ src/qml/ThumbnailImage.qml 2015-12-08 17:14:16 +0000 |
1003 | @@ -0,0 +1,49 @@ |
1004 | +/* |
1005 | + * Copyright 2012-2015 Canonical Ltd. |
1006 | + * |
1007 | + * This file is part of messaging-app. |
1008 | + * |
1009 | + * messaging-app is free software; you can redistribute it and/or modify |
1010 | + * it under the terms of the GNU General Public License as published by |
1011 | + * the Free Software Foundation; version 3. |
1012 | + * |
1013 | + * messaging-app is distributed in the hope that it will be useful, |
1014 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1015 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1016 | + * GNU General Public License for more details. |
1017 | + * |
1018 | + * You should have received a copy of the GNU General Public License |
1019 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1020 | + */ |
1021 | + |
1022 | +import QtQuick 2.0 |
1023 | +import Ubuntu.Components 1.3 |
1024 | + |
1025 | +UbuntuShape { |
1026 | + id: thumbnail |
1027 | + property int index |
1028 | + property string filePath |
1029 | + |
1030 | + signal pressAndHold() |
1031 | + |
1032 | + width: childrenRect.width |
1033 | + height: childrenRect.height |
1034 | + |
1035 | + image: Image { |
1036 | + id: avatarImage |
1037 | + width: units.gu(8) |
1038 | + height: units.gu(8) |
1039 | + sourceSize.height: height |
1040 | + sourceSize.width: width |
1041 | + fillMode: Image.PreserveAspectCrop |
1042 | + source: filePath |
1043 | + asynchronous: true |
1044 | + } |
1045 | + MouseArea { |
1046 | + anchors.fill: parent |
1047 | + onPressAndHold: { |
1048 | + mouse.accept = true |
1049 | + thumbnail.pressAndHold() |
1050 | + } |
1051 | + } |
1052 | +} |
1053 | |
1054 | === added file 'src/qml/ThumbnailUnknown.qml' |
1055 | --- src/qml/ThumbnailUnknown.qml 1970-01-01 00:00:00 +0000 |
1056 | +++ src/qml/ThumbnailUnknown.qml 2015-12-08 17:14:16 +0000 |
1057 | @@ -0,0 +1,45 @@ |
1058 | +/* |
1059 | + * Copyright 2012-2015 Canonical Ltd. |
1060 | + * |
1061 | + * This file is part of messaging-app. |
1062 | + * |
1063 | + * messaging-app is free software; you can redistribute it and/or modify |
1064 | + * it under the terms of the GNU General Public License as published by |
1065 | + * the Free Software Foundation; version 3. |
1066 | + * |
1067 | + * messaging-app is distributed in the hope that it will be useful, |
1068 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1069 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1070 | + * GNU General Public License for more details. |
1071 | + * |
1072 | + * You should have received a copy of the GNU General Public License |
1073 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1074 | + */ |
1075 | + |
1076 | +import QtQuick 2.0 |
1077 | +import Ubuntu.Components 1.3 |
1078 | + |
1079 | +UbuntuShape { |
1080 | + id: thumbnail |
1081 | + property int index |
1082 | + property string filePath |
1083 | + |
1084 | + signal pressAndHold() |
1085 | + |
1086 | + width: units.gu(8) |
1087 | + height: units.gu(8) |
1088 | + |
1089 | + Icon { |
1090 | + anchors.centerIn: parent |
1091 | + width: units.gu(6) |
1092 | + height: units.gu(6) |
1093 | + name: "attachment" |
1094 | + } |
1095 | + MouseArea { |
1096 | + anchors.fill: parent |
1097 | + onPressAndHold: { |
1098 | + mouse.accept = true |
1099 | + thumbnail.pressAndHold() |
1100 | + } |
1101 | + } |
1102 | +} |
1103 | |
1104 | === added file 'src/qml/TransparentButton.qml' |
1105 | --- src/qml/TransparentButton.qml 1970-01-01 00:00:00 +0000 |
1106 | +++ src/qml/TransparentButton.qml 2015-12-08 17:14:16 +0000 |
1107 | @@ -0,0 +1,86 @@ |
1108 | +/* |
1109 | + * Copyright 2015 Canonical Ltd. |
1110 | + * |
1111 | + * This file is part of messaging-app. |
1112 | + * |
1113 | + * messaging-app is free software; you can redistribute it and/or modify |
1114 | + * it under the terms of the GNU General Public License as published by |
1115 | + * the Free Software Foundation; version 3. |
1116 | + * |
1117 | + * messaging-app is distributed in the hope that it will be useful, |
1118 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1119 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1120 | + * GNU General Public License for more details. |
1121 | + * |
1122 | + * You should have received a copy of the GNU General Public License |
1123 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
1124 | + */ |
1125 | + |
1126 | +import QtQuick 2.0 |
1127 | +import Ubuntu.Components 1.3 |
1128 | + |
1129 | +Item { |
1130 | + id: button |
1131 | + |
1132 | + width: icon.width |
1133 | + height: icon.height + label.height + spacing |
1134 | + |
1135 | + property alias iconName: icon.name |
1136 | + property alias iconSource: icon.source |
1137 | + property alias iconColor: icon.color |
1138 | + property int iconSize: units.gu(2) |
1139 | + property alias iconRotation: icon.rotation |
1140 | + property alias text: label.text |
1141 | + property alias textSize: label.font.pixelSize |
1142 | + property int spacing: 0 |
1143 | + |
1144 | + signal clicked() |
1145 | + signal pressed() |
1146 | + signal released() |
1147 | + |
1148 | + Icon { |
1149 | + id: icon |
1150 | + |
1151 | + anchors { |
1152 | + left: parent.left |
1153 | + right: parent.right |
1154 | + top: parent.top |
1155 | + } |
1156 | + |
1157 | + height: iconSize |
1158 | + width: iconSize |
1159 | + color: "gray" |
1160 | + Behavior on rotation { |
1161 | + UbuntuNumberAnimation { } |
1162 | + } |
1163 | + } |
1164 | + |
1165 | + MouseArea { |
1166 | + anchors { |
1167 | + fill: parent |
1168 | + margins: units.gu(-2) |
1169 | + } |
1170 | + onClicked: { |
1171 | + mouse.accepted = true |
1172 | + button.clicked() |
1173 | + } |
1174 | + |
1175 | + onPressed: button.pressed() |
1176 | + onReleased: button.released() |
1177 | + } |
1178 | + |
1179 | + Text { |
1180 | + id: label |
1181 | + color: "gray" |
1182 | + height: text !== "" ? paintedHeight : 0 |
1183 | + anchors { |
1184 | + left: parent.left |
1185 | + right: parent.right |
1186 | + bottom: parent.bottom |
1187 | + } |
1188 | + horizontalAlignment: Text.AlignHCenter |
1189 | + verticalAlignment: Text.AlignBottom |
1190 | + font.family: "Ubuntu" |
1191 | + font.pixelSize: FontUtils.sizeToPixels("small") |
1192 | + } |
1193 | +} |
FAILED: Continuous integration, rev:443 jenkins. qa.ubuntu. com/job/ messaging- app-ci/ 734/ jenkins. qa.ubuntu. com/job/ generic- deb-autopilot- vivid-touch/ 5305/console jenkins. qa.ubuntu. com/job/ messaging- app-vivid- i386-ci/ 247/console jenkins. qa.ubuntu. com/job/ generic- mediumtests- builder- vivid-armhf/ 5325/console
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/messaging- app-ci/ 734/rebuild
http://