Merge lp:~artmello/messaging-app/messaging-app-video_attachment into lp:messaging-app

Proposed by Arthur Mello
Status: Merged
Merged at revision: 488
Proposed branch: lp:~artmello/messaging-app/messaging-app-video_attachment
Merge into: lp:messaging-app
Prerequisite: lp:~boiko/messaging-app/more_attachment_types
Diff against target: 1483 lines (+1035/-123)
20 files modified
debian/control (+2/-0)
src/CMakeLists.txt (+2/-0)
src/fileoperations.cpp (+48/-0)
src/fileoperations.h (+39/-0)
src/messagingapplication.cpp (+28/-1)
src/messagingapplication.h (+7/-1)
src/qml/AttachmentPanel.qml (+2/-3)
src/qml/ComposeBar.qml (+2/-0)
src/qml/MMS/MMSImage.qml (+1/-0)
src/qml/MMS/MMSVideo.qml (+60/-44)
src/qml/MMS/PreviewerImage.qml (+183/-8)
src/qml/MMS/PreviewerVideo.qml (+124/-33)
src/qml/MMSDelegate.qml (+6/-7)
src/qml/ThumbnailVideo.qml (+76/-0)
src/qml/messaging-app.qml (+3/-1)
tests/qml/CMakeLists.txt (+34/-25)
tests/qml/tst_MMSDelegate.qml (+167/-0)
tests/qml/tst_PreviewerImage.qml (+103/-0)
tests/qml/tst_PreviewerVideo.qml (+87/-0)
tests/qml/tst_QmlTests.cpp (+61/-0)
To merge this branch: bzr merge lp:~artmello/messaging-app/messaging-app-video_attachment
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Needs Fixing
Tiago Salem Herrmann (community) Needs Fixing
Review via email: mp+278476@code.launchpad.net

Commit message

Add video attachment delegates

Description of the change

Add video attachment delegates

To post a comment you must log in.
476. By Arthur Mello

Update headers

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
477. By Arthur Mello

Add initial qml test

478. By Arthur Mello

Change on MMSDelegate to look for participants from messageData

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Tiago Salem Herrmann (tiagosh) :
review: Needs Fixing
479. By Arthur Mello

Add QML tests for MMSDelegate

480. By Arthur Mello

Add PreviewerImage QML tests

481. By Arthur Mello

Merge with lp:~boiko/messaging-app/more_attachment_types/

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
482. By Arthur Mello

Add TODO message for FileOperations
Remove mimetype check used for testing

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
483. By Arthur Mello

Change QML test structure so we could include messaingapp.private

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
484. By Arthur Mello

Fix build

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
485. By Arthur Mello

Add PreviewerVideo qml tests

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
486. By Arthur Mello

Merge with parent

487. By Arthur Mello

Add build dep

488. By Arthur Mello

Add build dep

489. By Arthur Mello

Fix QML test

490. By Arthur Mello

Fix QML tests

491. By Arthur Mello

Add sample file

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
492. By Arthur Mello

Merge with lp:~boiko/messaging-app/more_attachment_types

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
493. By Arthur Mello

Add Video Thumbnail

494. By Arthur Mello

Fix typo

495. By Arthur Mello

Show ActivityIndicator while loading thumbnail
Fix thumbnail path

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
496. By Arthur Mello

Use VideoOutput instead of Video QML component

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
497. By Arthur Mello

Merge with parent branch

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
498. By Arthur Mello

Merge with parent branch

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/control'
2--- debian/control 2015-09-11 14:25:57 +0000
3+++ debian/control 2015-12-08 18:33:04 +0000
4@@ -21,8 +21,10 @@
5 qtdeclarative5-ubuntu-telephony0.1 | qtdeclarative5-ubuntu-telephony-plugin,
6 qtdeclarative5-ubuntu-content1,
7 qtdeclarative5-ubuntu-addressbook0.1,
8+ qtdeclarative5-ubuntu-thumbnailer0.1,
9 qtdeclarative5-qtcontacts-plugin,
10 qml-module-qt-labs-settings,
11+ qml-module-qtmultimedia,
12 qtpim5-dev,
13 xvfb,
14 Standards-Version: 3.9.4
15
16=== modified file 'src/CMakeLists.txt'
17--- src/CMakeLists.txt 2015-02-24 13:33:31 +0000
18+++ src/CMakeLists.txt 2015-12-08 18:33:04 +0000
19@@ -1,10 +1,12 @@
20 set(MESSAGING_APP messaging-app)
21
22 set(messaging_app_HDRS
23+ fileoperations.h
24 messagingapplication.h
25 )
26
27 set(messaging_app_SRCS
28+ fileoperations.cpp
29 messagingapplication.cpp
30 main.cpp
31 )
32
33=== added file 'src/fileoperations.cpp'
34--- src/fileoperations.cpp 1970-01-01 00:00:00 +0000
35+++ src/fileoperations.cpp 2015-12-08 18:33:04 +0000
36@@ -0,0 +1,48 @@
37+/*
38+ * Copyright (C) 2015 Canonical, Ltd.
39+ *
40+ * Authors:
41+ * Arthur Mello <arthur.mello@canonical.com>
42+ *
43+ * This file is part of messaging-app.
44+ *
45+ * messaging-app is free software; you can redistribute it and/or modify
46+ * it under the terms of the GNU General Public License as published by
47+ * the Free Software Foundation; version 3.
48+ *
49+ * messaging-app is distributed in the hope that it will be useful,
50+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
51+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
52+ * GNU General Public License for more details.
53+ *
54+ * You should have received a copy of the GNU General Public License
55+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
56+ */
57+
58+#include "fileoperations.h"
59+
60+#include <QDir>
61+#include <QFile>
62+#include <QTemporaryFile>
63+
64+FileOperations::FileOperations(QObject *parent)
65+ : QObject(parent)
66+{
67+}
68+
69+FileOperations::~FileOperations()
70+{
71+}
72+
73+QString FileOperations::getTemporaryFile(const QString &fileExtension) const
74+{
75+ //TODO remove once lp:1420728 is fixed
76+ QTemporaryFile tmp(QDir::tempPath() + "/tmpXXXXXX" + fileExtension);
77+ tmp.open();
78+ return tmp.fileName();
79+}
80+
81+bool FileOperations::link(const QString &from, const QString &to)
82+{
83+ return QFile::link(from, to);
84+}
85
86=== added file 'src/fileoperations.h'
87--- src/fileoperations.h 1970-01-01 00:00:00 +0000
88+++ src/fileoperations.h 2015-12-08 18:33:04 +0000
89@@ -0,0 +1,39 @@
90+/*
91+ * Copyright (C) 2015 Canonical, Ltd.
92+ *
93+ * Authors:
94+ * Arthur Mello <arthur.mello@canonical.com>
95+ *
96+ * This file is part of messaging-app.
97+ *
98+ * messaging-app is free software; you can redistribute it and/or modify
99+ * it under the terms of the GNU General Public License as published by
100+ * the Free Software Foundation; version 3.
101+ *
102+ * messaging-app is distributed in the hope that it will be useful,
103+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
104+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
105+ * GNU General Public License for more details.
106+ *
107+ * You should have received a copy of the GNU General Public License
108+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
109+ */
110+
111+#ifndef FILEOPERATIONS_H
112+#define FILEOPERATIONS_H
113+
114+#include <QObject>
115+
116+class FileOperations : public QObject
117+{
118+ Q_OBJECT
119+
120+public:
121+ FileOperations(QObject *parent = 0);
122+ ~FileOperations();
123+
124+ Q_INVOKABLE QString getTemporaryFile(const QString &fileExtension) const;
125+ Q_INVOKABLE bool link(const QString &from, const QString &to);
126+};
127+
128+#endif // FILEOPERATIONS_H
129
130=== modified file 'src/messagingapplication.cpp'
131--- src/messagingapplication.cpp 2015-11-23 19:51:16 +0000
132+++ src/messagingapplication.cpp 2015-12-08 18:33:04 +0000
133@@ -1,5 +1,5 @@
134 /*
135- * Copyright (C) 2012 Canonical, Ltd.
136+ * Copyright (C) 2012-2015 Canonical, Ltd.
137 *
138 * This file is part of messaging-app.
139 *
140@@ -17,6 +17,7 @@
141 */
142
143 #include "messagingapplication.h"
144+#include "fileoperations.h"
145
146 #include <libnotify/notify.h>
147
148@@ -65,12 +66,24 @@
149 }
150 }
151
152+static QObject* FileOperations_singleton_factory(QQmlEngine* engine, QJSEngine* scriptEngine)
153+{
154+ Q_UNUSED(engine);
155+ Q_UNUSED(scriptEngine);
156+ return new FileOperations();
157+}
158+
159 MessagingApplication::MessagingApplication(int &argc, char **argv)
160 : QGuiApplication(argc, argv), m_view(0), m_applicationIsReady(false)
161 {
162 setApplicationName("MessagingApp");
163 }
164
165+bool MessagingApplication::fullscreen() const
166+{
167+ return m_view->windowState() == Qt::WindowFullScreen;
168+}
169+
170 bool MessagingApplication::setup()
171 {
172 installIconPath();
173@@ -133,6 +146,9 @@
174 }
175 }
176
177+ const char* uri = "messagingapp.private";
178+ qmlRegisterSingletonType<FileOperations>(uri, 0, 1, "FileOperations", FileOperations_singleton_factory);
179+
180 m_view = new QQuickView();
181 QObject::connect(m_view, SIGNAL(statusChanged(QQuickView::Status)), this, SLOT(onViewStatusChanged(QQuickView::Status)));
182 QObject::connect(m_view->engine(), SIGNAL(quit()), SLOT(quit()));
183@@ -176,6 +192,17 @@
184 }
185 }
186
187+void MessagingApplication::setFullscreen(bool fullscreen)
188+{
189+ if (fullscreen) {
190+ m_view->setWindowState(Qt::WindowFullScreen);
191+ } else {
192+ m_view->setWindowState(Qt::WindowNoState);
193+ }
194+
195+ Q_EMIT fullscreenChanged();
196+}
197+
198 void MessagingApplication::onViewStatusChanged(QQuickView::Status status)
199 {
200 if (status != QQuickView::Ready) {
201
202=== modified file 'src/messagingapplication.h'
203--- src/messagingapplication.h 2015-11-18 16:36:51 +0000
204+++ src/messagingapplication.h 2015-12-08 18:33:04 +0000
205@@ -1,5 +1,5 @@
206 /*
207- * Copyright (C) 2012-2013 Canonical, Ltd.
208+ * Copyright (C) 2012-2015 Canonical, Ltd.
209 *
210 * This file is part of messaging-app.
211 *
212@@ -26,13 +26,18 @@
213 class MessagingApplication : public QGuiApplication
214 {
215 Q_OBJECT
216+ Q_PROPERTY(bool fullscreen READ fullscreen WRITE setFullscreen NOTIFY fullscreenChanged)
217
218 public:
219 MessagingApplication(int &argc, char **argv);
220 virtual ~MessagingApplication();
221
222+ bool fullscreen() const;
223 bool setup();
224
225+Q_SIGNALS:
226+ void fullscreenChanged();
227+
228 public Q_SLOTS:
229 void activateWindow();
230 void parseArgument(const QString &arg);
231@@ -41,6 +46,7 @@
232 void showNotificationMessage(const QString &message, const QString &icon = QString());
233
234 private Q_SLOTS:
235+ void setFullscreen(bool fullscreen);
236 void onViewStatusChanged(QQuickView::Status status);
237 void onApplicationReady();
238
239
240=== modified file 'src/qml/AttachmentPanel.qml'
241--- src/qml/AttachmentPanel.qml 2015-12-08 18:33:04 +0000
242+++ src/qml/AttachmentPanel.qml 2015-12-08 18:33:04 +0000
243@@ -102,8 +102,7 @@
244 }
245 }
246
247- // FIXME: re-enable that once we have proper delegates
248- /*TransparentButton {
249+ TransparentButton {
250 id: videoButton
251 objectName: "videoButton"
252 iconName: "stock_video"
253@@ -114,7 +113,7 @@
254 onClicked: {
255 contentImporter.requestVideo()
256 }
257- }*/
258+ }
259
260 // FIXME: enable generic file sharing if we ever support it
261 /*TransparentButton {
262
263=== modified file 'src/qml/ComposeBar.qml'
264--- src/qml/ComposeBar.qml 2015-12-08 18:33:04 +0000
265+++ src/qml/ComposeBar.qml 2015-12-08 18:33:04 +0000
266@@ -204,6 +204,8 @@
267 return Qt.resolvedUrl("ThumbnailContact.qml")
268 case ContentType.Pictures:
269 return Qt.resolvedUrl("ThumbnailImage.qml")
270+ case ContentType.Videos:
271+ return Qt.resolvedUrl("ThumbnailVideo.qml")
272 case ContentType.Unknown:
273 return Qt.resolvedUrl("ThumbnailUnknown.qml")
274 default:
275
276=== modified file 'src/qml/MMS/MMSImage.qml'
277--- src/qml/MMS/MMSImage.qml 2015-09-14 13:51:27 +0000
278+++ src/qml/MMS/MMSImage.qml 2015-12-08 18:33:04 +0000
279@@ -34,6 +34,7 @@
280
281 image: Image {
282 id: imageAttachment
283+ objectName: "imageAttachment"
284
285 fillMode: Image.PreserveAspectCrop
286 smooth: true
287
288=== modified file 'src/qml/MMS/MMSVideo.qml'
289--- src/qml/MMS/MMSVideo.qml 2015-09-14 13:51:27 +0000
290+++ src/qml/MMS/MMSVideo.qml 2015-12-08 18:33:04 +0000
291@@ -1,5 +1,5 @@
292 /*
293- * Copyright 2012, 2013, 2014 Canonical Ltd.
294+ * Copyright 2012-2015 Canonical Ltd.
295 *
296 * This file is part of messaging-app.
297 *
298@@ -18,64 +18,80 @@
299
300 import QtQuick 2.2
301 import Ubuntu.Components 1.3
302-import QtMultimedia 5.0
303-import ".."
304+import Ubuntu.Thumbnailer 0.1
305
306 MMSBase {
307 id: videoDelegate
308
309 previewer: "MMS/PreviewerVideo.qml"
310- anchors.left: parent.left
311- anchors.right: parent.right
312- height: bubble.height + units.gu(1)
313+ height: videoAttachment.height
314+ width: videoAttachment.width
315
316- Item {
317+ UbuntuShape {
318 id: bubble
319 anchors.top: parent.top
320- width: videoOutput.width + units.gu(3)
321- height: videoOutput.height + units.gu(2)
322-
323- MediaPlayer {
324- id: video
325- autoLoad: true
326- autoPlay: false
327- source: attachment.filePath
328- onStatusChanged: {
329- if (status === MediaPlayer.Loaded) {
330- // FIXME: there is no way to show the thumbnail
331- video.play(); video.stop();
332-
333- // resize videoOutput, as width is not set
334- // properly when using PreserveAspectFit
335- if (videoOutput.height > units.gu(25)) {
336- var percentageResized = units.gu(25)*100/(metaData.resolution.height)
337- videoOutput.height = units.gu(25)
338- videoOutput.width = (metaData.resolution.width*percentageResized)/100
339- }
340- if (videoOutput.width > units.gu(35)) {
341- percentageResized = units.gu(35)*100/(metaData.resolution.width)
342- videoOutput.width = units.gu(35)
343- videoOutput.height = (metaData.resolution.height*percentageResized)/100
344- }
345+ width: image.width
346+ height: image.height
347+
348+ image: Image {
349+ id: videoAttachment
350+ objectName: "videoAttachment"
351+
352+ fillMode: Image.PreserveAspectCrop
353+ smooth: true
354+ source: "image://thumbnailer/" + attachment.filePath
355+ visible: false
356+ asynchronous: true
357+ height: Math.min(implicitHeight, units.gu(14))
358+ width: Math.min(implicitWidth, units.gu(27))
359+ cache: false
360+
361+ sourceSize.width: units.gu(27)
362+ sourceSize.height: units.gu(27)
363+
364+ onStatusChanged: {
365+ if (status === Image.Error) {
366+ source = "image://theme/image-missing"
367+ width = 128
368+ height = 128
369 }
370 }
371 }
372- VideoOutput {
373- id: videoOutput
374- source: video
375+
376+ Icon {
377+ objectName: "playbackStartIcon"
378+ width: units.gu(3)
379+ height: units.gu(3)
380 anchors.centerIn: parent
381- anchors.horizontalCenterOffset: incoming ? units.gu(0.5) : -units.gu(0.5)
382+ name: "media-playback-start"
383+ color: "white"
384+ opacity: 0.8
385 }
386
387 Rectangle {
388- color: "black"
389- opacity: 0.8
390- anchors.fill: videoOutput
391- Icon {
392- name: "media-playback-start"
393- width: units.gu(4)
394- height: units.gu(4)
395- anchors.centerIn: parent
396+ visible: videoDelegate.lastItem
397+ gradient: Gradient {
398+ GradientStop { position: 0.0; color: "transparent" }
399+ GradientStop { position: 1.0; color: "gray" }
400+ }
401+
402+ anchors {
403+ bottom: parent.bottom
404+ left: parent.left
405+ right: parent.right
406+ }
407+ height: units.gu(2)
408+ radius: bubble.height * 0.1
409+ Label {
410+ anchors{
411+ left: parent.left
412+ bottom: parent.bottom
413+ leftMargin: incoming ? units.gu(2) : units.gu(1)
414+ bottomMargin: units.gu(0.5)
415+ }
416+ fontSize: "xx-small"
417+ text: Qt.formatTime(timestamp).toLowerCase()
418+ color: "white"
419 }
420 }
421 }
422
423=== modified file 'src/qml/MMS/PreviewerImage.qml'
424--- src/qml/MMS/PreviewerImage.qml 2015-09-14 13:51:27 +0000
425+++ src/qml/MMS/PreviewerImage.qml 2015-12-08 18:33:04 +0000
426@@ -1,5 +1,5 @@
427 /*
428- * Copyright 2012, 2013, 2014 Canonical Ltd.
429+ * Copyright 2012-2015 Canonical Ltd.
430 *
431 * This file is part of messaging-app.
432 *
433@@ -19,18 +19,193 @@
434 import QtQuick 2.2
435 import Ubuntu.Components 1.3
436 import Ubuntu.Content 0.1
437+import Ubuntu.Thumbnailer 0.1
438 import ".."
439
440 Previewer {
441+ id: imagePreviewer
442+
443+ Component.onCompleted: application.fullscreen = true
444+ Component.onDestruction: application.fullscreen = false
445+
446+ Connections {
447+ target: application
448+ onFullscreenChanged: imagePreviewer.head.visible = !application.fullscreen
449+ }
450+
451 title: i18n.tr("Image Preview")
452 clip: true
453- Image {
454- anchors.centerIn: parent
455+
456+ Rectangle {
457 anchors.fill: parent
458- fillMode: Image.PreserveAspectFit
459- source: attachment.filePath
460- cache: false
461- sourceSize.width: parent.width
462- sourceSize.height: parent.height
463+ color: "black"
464+ }
465+
466+ Item {
467+ id: imageItem
468+ property bool pinchInProgress: zoomPinchArea.active
469+ property size thumbSize: Qt.size(viewer.width * 1.05, viewer.height * 1.05)
470+
471+ onWidthChanged: {
472+ // Only change thumbSize if width increases more than 5%
473+ // that way we do not reload image for small resizes
474+ if (width > thumbSize.width) {
475+ thumbSize = Qt.size(width * 1.05, height * 1.05);
476+ }
477+ }
478+
479+ onHeightChanged: {
480+ // Only change thumbSize if height increases more than 5%
481+ // that way we do not reload image for small resizes
482+ if (height > thumbSize.height) {
483+ thumbSize = Qt.size(width * 1.05, height * 1.05);
484+ }
485+ }
486+
487+ function zoomIn(centerX, centerY, factor) {
488+ flickable.scaleCenterX = centerX / (flickable.sizeScale * flickable.width);
489+ flickable.scaleCenterY = centerY / (flickable.sizeScale * flickable.height);
490+ flickable.sizeScale = factor;
491+ }
492+
493+ function zoomOut() {
494+ if (flickable.sizeScale != 1.0) {
495+ flickable.scaleCenterX = flickable.contentX / flickable.width / (flickable.sizeScale - 1);
496+ flickable.scaleCenterY = flickable.contentY / flickable.height / (flickable.sizeScale - 1);
497+ flickable.sizeScale = 1.0;
498+ }
499+ }
500+
501+ width: parent.width
502+ height: parent.height
503+
504+ ActivityIndicator {
505+ objectName: "imageActivityIndicator"
506+ anchors.centerIn: parent
507+ visible: running
508+ running: image.status != Image.Ready
509+ }
510+
511+ PinchArea {
512+ id: zoomPinchArea
513+ anchors.fill: parent
514+
515+ property real initialZoom
516+ property real maximumScale: 3.0
517+ property real minimumZoom: 1.0
518+ property real maximumZoom: 3.0
519+ property bool active: false
520+ property var center
521+
522+ onPinchStarted: {
523+ active = true;
524+ initialZoom = flickable.sizeScale;
525+ center = zoomPinchArea.mapToItem(media, pinch.startCenter.x, pinch.startCenter.y);
526+ imageItem.zoomIn(center.x, center.y, initialZoom);
527+ }
528+ onPinchUpdated: {
529+ var zoomFactor = MathUtils.clamp(initialZoom * pinch.scale, minimumZoom, maximumZoom);
530+ flickable.sizeScale = zoomFactor;
531+ }
532+ onPinchFinished: {
533+ active = false;
534+ }
535+
536+ Flickable {
537+ id: flickable
538+ anchors.fill: parent
539+ contentWidth: media.width
540+ contentHeight: media.height
541+ contentX: (sizeScale - 1) * scaleCenterX * width
542+ contentY: (sizeScale - 1) * scaleCenterY * height
543+ interactive: !imageItem.pinchInProgress
544+
545+ property real sizeScale: 1.0
546+ property real scaleCenterX: 0.0
547+ property real scaleCenterY: 0.0
548+
549+ Behavior on sizeScale {
550+ enabled: !imageItem.pinchInProgress
551+ UbuntuNumberAnimation {duration: UbuntuAnimation.FastDuration}
552+ }
553+ Behavior on scaleCenterX {
554+ UbuntuNumberAnimation {duration: UbuntuAnimation.FastDuration}
555+ }
556+ Behavior on scaleCenterY {
557+ UbuntuNumberAnimation {duration: UbuntuAnimation.FastDuration}
558+ }
559+
560+ Item {
561+ id: media
562+
563+ width: flickable.width * flickable.sizeScale
564+ height: flickable.height * flickable.sizeScale
565+
566+ Image {
567+ id: image
568+ objectName: "thumbnailImage"
569+ anchors.fill: parent
570+ asynchronous: true
571+ cache: false
572+ source: "image://thumbnailer/%1".arg(attachment.filePath.toString())
573+ sourceSize {
574+ width: imageItem.thumbSize.width
575+ height: imageItem.thumbSize.height
576+ }
577+ fillMode: Image.PreserveAspectFit
578+ opacity: status == Image.Ready ? 1.0 : 0.0
579+ Behavior on opacity { UbuntuNumberAnimation {duration: UbuntuAnimation.FastDuration} }
580+ }
581+
582+ Image {
583+ id: highResolutionImage
584+ objectName: "highResolutionImage"
585+ anchors.fill: parent
586+ asynchronous: true
587+ cache: false
588+ source: flickable.sizeScale > 1.0 ? attachment.filePath : ""
589+ sourceSize {
590+ width: width
591+ height: height
592+ }
593+ fillMode: Image.PreserveAspectFit
594+ }
595+ }
596+
597+ MouseArea {
598+ id: imageMouseArea
599+ anchors.fill: parent
600+
601+ property bool clickAccepted: false
602+
603+ onDoubleClicked: {
604+ if (imageMouseArea.clickAccepted) {
605+ return
606+ }
607+
608+ clickTimer.stop()
609+
610+ if (flickable.sizeScale < zoomPinchArea.maximumZoom) {
611+ imageItem.zoomIn(mouse.x, mouse.y, zoomPinchArea.maximumZoom);
612+ } else {
613+ imageItem.zoomOut();
614+ }
615+ }
616+ onClicked: {
617+ imageMouseArea.clickAccepted = false
618+ clickTimer.start()
619+ }
620+ }
621+
622+ Timer {
623+ id: clickTimer
624+ interval: 200
625+ onTriggered: {
626+ imageMouseArea.clickAccepted = true
627+ application.fullscreen = !application.fullscreen
628+ }
629+ }
630+ }
631+ }
632 }
633 }
634
635=== modified file 'src/qml/MMS/PreviewerVideo.qml'
636--- src/qml/MMS/PreviewerVideo.qml 2015-09-14 13:51:27 +0000
637+++ src/qml/MMS/PreviewerVideo.qml 2015-12-08 18:33:04 +0000
638@@ -1,5 +1,5 @@
639 /*
640- * Copyright 2012, 2013, 2014 Canonical Ltd.
641+ * Copyright 2012-2015 Canonical Ltd.
642 *
643 * This file is part of messaging-app.
644 *
645@@ -17,61 +17,152 @@
646 */
647
648 import QtQuick 2.2
649+import QtMultimedia 5.0
650 import Ubuntu.Components 1.3
651-import QtMultimedia 5.0
652+import Ubuntu.Content 0.1
653+import Ubuntu.Thumbnailer 0.1
654+import messagingapp.private 0.1
655 import ".."
656
657 Previewer {
658+ id: videoPreviewer
659+
660 title: i18n.tr("Video Preview")
661- // This previewer implements only basic video controls: play/pause/rewind
662- onActionTriggered: video.pause()
663- MediaPlayer {
664- id: video
665- autoLoad: true
666- autoPlay: true
667- source: attachment.filePath
668- }
669- VideoOutput {
670- id: videoOutput
671- source: video
672- anchors.fill: parent
673+ clip: true
674+
675+ Component.onCompleted: {
676+ application.fullscreen = true
677+ // Load Video player after toggling fullscreen to reduce flickering
678+ videoLoader.active = true
679+ }
680+ Component.onDestruction: application.fullscreen = false
681+
682+ Connections {
683+ target: application
684+ onFullscreenChanged: {
685+ videoPreviewer.head.visible = !application.fullscreen
686+ toolbar.collapsed = application.fullscreen
687+ }
688+ }
689+
690+ Rectangle {
691+ anchors.fill: parent
692+ color: "black"
693+ }
694+
695+ Loader {
696+ id: videoLoader
697+
698+ anchors.fill: parent
699+ active: false
700+ sourceComponent: videoComponent
701+
702+ onStatusChanged: {
703+ if (status == Loader.Ready) {
704+ var tmpFile = FileOperations.getTemporaryFile(".mp4")
705+ if (FileOperations.link(attachment.filePath, tmpFile)) {
706+ videoLoader.item.source = tmpFile
707+ } else {
708+ console.log("MMSVideo: Failed to link", attachment.filePath, "to", tmpFile)
709+ }
710+ }
711+ }
712+
713+ Component {
714+ id: videoComponent
715+
716+ Item {
717+ id: videoPlayer
718+ objectName: "videoPlayer"
719+
720+ property alias source: player.source
721+ property alias playbackState: player.playbackState
722+
723+ function play() { player.play() }
724+ function pause() { player.pause() }
725+ function stop() { player.stop() }
726+
727+ anchors.fill: parent
728+
729+ MediaPlayer {
730+ id: player
731+ autoPlay: true
732+ }
733+
734+ VideoOutput {
735+ id: videoOutput
736+ anchors.fill: parent
737+ source: player
738+ }
739+ }
740+ }
741 }
742
743 MouseArea {
744- id: playArea
745- anchors.fill: parent
746- onPressed: {
747- if (video.playbackState === MediaPlayer.PlayingState) {
748- video.pause()
749- }
750+ anchors {
751+ top: parent.top
752+ bottom: toolbar.top
753+ left: parent.left
754+ right: parent.right
755 }
756+ onClicked: application.fullscreen = !application.fullscreen
757 }
758
759 Rectangle {
760- color: "black"
761- visible: video.playbackState !== MediaPlayer.PlayingState
762+ id: toolbar
763+ objectName: "toolbar"
764+
765+ property bool collapsed: false
766+
767+ anchors.bottom: parent.bottom
768+
769+ width: parent.width
770+ height: collapsed ? 0 : units.gu(7)
771+ Behavior on height { UbuntuNumberAnimation {} }
772+
773+ color: "gray"
774 opacity: 0.8
775- anchors.fill: videoOutput
776+
777 Row {
778- anchors.centerIn: parent
779+ anchors {
780+ top: parent.top
781+ bottom: parent.bottom
782+ horizontalCenter: parent.horizontalCenter
783+ }
784+
785+ spacing: units.gu(2)
786+
787 Icon {
788- name: "media-playback-pause"
789- width: units.gu(5)
790- height: units.gu(5)
791+ anchors.verticalCenter: parent.verticalCenter
792+ width: toolbar.collapsed ? 0 : units.gu(5)
793+ height: width
794+ Behavior on width { UbuntuNumberAnimation {} }
795+ Behavior on height { UbuntuNumberAnimation {} }
796+ name: videoLoader.item && videoLoader.item.playbackState == MediaPlayer.PlayingState ? "media-playback-pause" : "media-playback-start"
797+ color: "white"
798 MouseArea {
799 anchors.fill: parent
800- onClicked: video.play();
801+ onClicked: {
802+ if (videoLoader.item.playbackState == MediaPlayer.PlayingState) {
803+ videoLoader.item.pause()
804+ } else {
805+ videoLoader.item.play()
806+ }
807+ }
808 }
809 }
810 Icon {
811- name: "media-seek-backward"
812- width: units.gu(5)
813- height: units.gu(5)
814+ anchors.verticalCenter: parent.verticalCenter
815+ width: toolbar.collapsed ? 0 : units.gu(5)
816+ height: width
817+ Behavior on width { UbuntuNumberAnimation {} }
818+ Behavior on height { UbuntuNumberAnimation {} }
819+ name: "media-playback-stop"
820+ color: "white"
821 MouseArea {
822 anchors.fill: parent
823 onClicked: {
824- video.stop();
825- video.play();
826+ videoLoader.item.stop()
827 }
828 }
829 }
830
831=== modified file 'src/qml/MMSDelegate.qml'
832--- src/qml/MMSDelegate.qml 2015-11-23 19:51:16 +0000
833+++ src/qml/MMSDelegate.qml 2015-12-08 18:33:04 +0000
834@@ -87,12 +87,6 @@
835 "data": attachment,
836 "delegateSource": "MMS/MMSImage.qml",
837 })
838- //} else if (startsWith(attachment.contentType, "video/")) {
839- // TODO: implement proper video attachment support
840- // dataAttachments.push({type: "video",
841- // data: attachment,
842- // delegateSource: "MMS/MMSVideo.qml",
843- // })
844 } else if (startsWith(attachment.contentType, "application/smil") ||
845 startsWith(attachment.contentType, "application/x-smil")) {
846 // smil files will always be ignored here
847@@ -102,6 +96,11 @@
848 "data": attachment,
849 "delegateSource": "MMS/MMSContact.qml"
850 })
851+ } else if (startsWith(attachment.contentType, "video/")) {
852+ root.dataAttachments.push({"type": "video",
853+ "data": attachment,
854+ "delegateSource": "MMS/MMSVideo.qml",
855+ })
856 } else {
857 root.dataAttachments.push({"type": "default",
858 "data": attachment,
859@@ -221,7 +220,7 @@
860 target: bubbleLoader.item
861 property: "sender"
862 value: messageData.sender.alias !== "" ? messageData.sender.alias : messageData.senderId
863- when: participants.length > 1 && bubbleLoader.status === Loader.Ready && messageData.senderId !== "self"
864+ when: messageData.participants.length > 1 && bubbleLoader.status === Loader.Ready && messageData.senderId !== "self"
865 }
866 }
867 }
868
869=== added file 'src/qml/ThumbnailVideo.qml'
870--- src/qml/ThumbnailVideo.qml 1970-01-01 00:00:00 +0000
871+++ src/qml/ThumbnailVideo.qml 2015-12-08 18:33:04 +0000
872@@ -0,0 +1,76 @@
873+/*
874+ * Copyright 2015 Canonical Ltd.
875+ *
876+ * This file is part of messaging-app.
877+ *
878+ * messaging-app is free software; you can redistribute it and/or modify
879+ * it under the terms of the GNU General Public License as published by
880+ * the Free Software Foundation; version 3.
881+ *
882+ * messaging-app is distributed in the hope that it will be useful,
883+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
884+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
885+ * GNU General Public License for more details.
886+ *
887+ * You should have received a copy of the GNU General Public License
888+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
889+ */
890+
891+import QtQuick 2.0
892+import Ubuntu.Components 1.3
893+import Ubuntu.Thumbnailer 0.1
894+
895+UbuntuShape {
896+ id: thumbnail
897+ property int index
898+ property string filePath
899+
900+ signal pressAndHold()
901+
902+ onFilePathChanged: videoImage.source = "image://thumbnailer/" + filePath
903+
904+ width: childrenRect.width
905+ height: childrenRect.height
906+
907+ image: Image {
908+ id: videoImage
909+
910+ width: units.gu(8)
911+ height: units.gu(8)
912+ sourceSize.width: width
913+ sourceSize.height: height
914+ fillMode: Image.PreserveAspectCrop
915+ asynchronous: true
916+
917+ onStatusChanged: {
918+ if (status === Image.Error) {
919+ source = "image://theme/image-missing"
920+ }
921+ }
922+ }
923+
924+ ActivityIndicator {
925+ anchors.centerIn: parent
926+ visible: running
927+ running: videoImage.status != Image.Ready
928+ }
929+
930+ Icon {
931+ width: units.gu(3)
932+ height: units.gu(3)
933+ anchors.centerIn: parent
934+ name: "media-playback-start"
935+ color: "white"
936+ visible: opacity > 0.0
937+ opacity: videoImage.status == Image.Ready ? 0.8 : 0.0
938+ Behavior on opacity { UbuntuNumberAnimation {duration: UbuntuAnimation.FastDuration} }
939+ }
940+
941+ MouseArea {
942+ anchors.fill: parent
943+ onPressAndHold: {
944+ mouse.accept = true
945+ thumbnail.pressAndHold()
946+ }
947+ }
948+}
949
950=== modified file 'src/qml/messaging-app.qml'
951--- src/qml/messaging-app.qml 2015-11-23 19:51:16 +0000
952+++ src/qml/messaging-app.qml 2015-12-08 18:33:04 +0000
953@@ -1,5 +1,5 @@
954 /*
955- * Copyright 2012-2013 Canonical Ltd.
956+ * Copyright 2012-2015 Canonical Ltd.
957 *
958 * This file is part of messaging-app.
959 *
960@@ -194,6 +194,8 @@
961 } else if (startsWith(contentType, "text/vcard") ||
962 startsWith(contentType, "text/x-vcard")) {
963 return ContentType.Contacts
964+ } else if (startsWith(contentType, "video/")) {
965+ return ContentType.Videos
966 }
967 return ContentType.Unknown
968 }
969
970=== modified file 'tests/qml/CMakeLists.txt'
971--- tests/qml/CMakeLists.txt 2015-08-13 18:34:55 +0000
972+++ tests/qml/CMakeLists.txt 2015-12-08 18:33:04 +0000
973@@ -1,33 +1,42 @@
974-find_program(QMLTESTRUNNER_BIN
975- NAMES qmltestrunner
976- PATHS /usr/lib/*/qt5/bin
977- NO_DEFAULT_PATH
978-)
979+find_package(Qt5Core REQUIRED)
980+find_package(Qt5Qml REQUIRED)
981+find_package(Qt5Quick REQUIRED)
982+find_package(Qt5QuickTest REQUIRED)
983+
984+set(XVFB_COMMAND)
985
986 find_program(XVFB_RUN_BIN
987 NAMES xvfb-run
988 )
989
990-macro(DECLARE_QML_TEST TST_NAME TST_QML_FILE)
991- add_test(NAME ${TST_NAME}
992- WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
993- COMMAND ${XVFB_RUN_BIN} -a -s "-screen 0 1024x768x24" ${QMLTESTRUNNER_BIN} -import ${qml_BINARY_DIR} -input ${CMAKE_CURRENT_SOURCE_DIR}/${TST_QML_FILE}
994- )
995-endmacro()
996-
997-if(QMLTESTRUNNER_BIN AND XVFB_RUN_BIN)
998- declare_qml_test("message_bubble" tst_MessageBubble.qml)
999- declare_qml_test("messages_view" tst_MessagesView.qml)
1000+if(XVFB_RUN_BIN)
1001+ set(XVFB_COMMAND ${XVFB_RUN_BIN} -s "-screen 0 1024x768x24" -a)
1002 else()
1003- if (NOT QMLTESTRUNNER_BIN)
1004- message(WARNING "Qml tests disabled: qmltestrunner not found")
1005- else()
1006- message(WARNING "Qml tests disabled: xvfb-run not found")
1007- endif()
1008+ message(WARNING "Qml tests disabled: xvfb-run not found")
1009 endif()
1010
1011-set(QML_TST_FILES
1012- tst_MessageBubble.qml
1013- tst_MessagesView.qml
1014-)
1015-add_custom_target(tst_QmlFiles ALL SOURCES ${QML_TST_FILES})
1016+set(TEST tst_QmlTests)
1017+
1018+set(SOURCES
1019+ ${messaging-app_SOURCE_DIR}/src/fileoperations.cpp
1020+ tst_QmlTests.cpp
1021+)
1022+
1023+add_executable(${TEST} ${SOURCES})
1024+
1025+include_directories(
1026+ ${messaging-app_SOURCE_DIR}/src
1027+ ${CMAKE_CURRENT_BINARY_DIR}
1028+ ${CMAKE_CURRENT_SOURCE_DIR}
1029+)
1030+
1031+target_link_libraries(${TEST}
1032+ Qt5::Core
1033+ Qt5::Qml
1034+ Qt5::Quick
1035+ Qt5::QuickTest
1036+)
1037+
1038+add_test(${TEST} ${XVFB_COMMAND} ${CMAKE_CURRENT_BINARY_DIR}/${TEST}
1039+ -input ${CMAKE_CURRENT_SOURCE_DIR}
1040+ -import ${CMAKE_BINARY_DIR}/src)
1041
1042=== added directory 'tests/qml/data'
1043=== added file 'tests/qml/data/sample.mp4'
1044Binary files tests/qml/data/sample.mp4 1970-01-01 00:00:00 +0000 and tests/qml/data/sample.mp4 2015-12-08 18:33:04 +0000 differ
1045=== added file 'tests/qml/data/sample.png'
1046Binary files tests/qml/data/sample.png 1970-01-01 00:00:00 +0000 and tests/qml/data/sample.png 2015-12-08 18:33:04 +0000 differ
1047=== added file 'tests/qml/tst_MMSDelegate.qml'
1048--- tests/qml/tst_MMSDelegate.qml 1970-01-01 00:00:00 +0000
1049+++ tests/qml/tst_MMSDelegate.qml 2015-12-08 18:33:04 +0000
1050@@ -0,0 +1,167 @@
1051+/*
1052+ * Copyright 2015 Canonical Ltd.
1053+ *
1054+ * Authors:
1055+ * Arthur Mello <arthur.mello@canonical.com>
1056+ *
1057+ * This file is part of messaging-app.
1058+ *
1059+ * messaging-app is free software; you can redistribute it and/or modify
1060+ * it under the terms of the GNU General Public License as published by
1061+ * the Free Software Foundation; version 3.
1062+ *
1063+ * messaging-app is distributed in the hope that it will be useful,
1064+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1065+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1066+ * GNU General Public License for more details.
1067+ *
1068+ * You should have received a copy of the GNU General Public License
1069+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1070+ */
1071+
1072+import QtQuick 2.2
1073+import QtTest 1.0
1074+import Ubuntu.Test 0.1
1075+
1076+import '../../src/qml/'
1077+
1078+Item {
1079+ id: root
1080+
1081+ width: units.gu(40)
1082+ height: units.gu(40)
1083+
1084+ MMSDelegate {
1085+ id: mmsDelegate
1086+ objectName: "mmsDelegate"
1087+
1088+ function startsWith(str, prefix) {
1089+ return str.toLowerCase().slice(0, prefix.length) === prefix.toLowerCase();
1090+ }
1091+
1092+ anchors.fill: parent
1093+
1094+ messageData: {
1095+ "participants": [],
1096+ "sender": {"alias": ""},
1097+ "textMessageAttachments": [],
1098+ }
1099+ }
1100+
1101+ UbuntuTestCase {
1102+ id: mmsImageDelegateTestCase
1103+ name: 'mmsImageDelegateTestCase'
1104+
1105+ when: windowShown
1106+
1107+ function test_load_image() {
1108+ mmsDelegate.messageData = {
1109+ "newEvent": false,
1110+ "participants": [],
1111+ "sender": {"alias": ""},
1112+ "senderId": "self",
1113+ "textMessage": "Message Delegate QML Test",
1114+ "textMessageAttachments": [
1115+ {
1116+ "contentType": "image/png",
1117+ "filePath": Qt.resolvedUrl("./data/sample.png")
1118+ }
1119+ ],
1120+ "textMessageStatus": 1,
1121+ "textReadTimestamp": new Date(),
1122+ "timestamp": new Date()
1123+ }
1124+
1125+ var image = findChild(mmsDelegate, "imageAttachment")
1126+ verify(image != null)
1127+ waitForRendering(image)
1128+ verify(image.source != "image://theme/image-missing")
1129+ }
1130+
1131+ function test_load_invalid_path() {
1132+ mmsDelegate.messageData = {
1133+ "newEvent": false,
1134+ "participants": [],
1135+ "sender": {"alias": ""},
1136+ "senderId": "self",
1137+ "textMessage": "Message Delegate QML Test",
1138+ "textMessageAttachments": [
1139+ {
1140+ "contentType": "image/png",
1141+ "filePath": "/wrong/path/file.png"
1142+ }
1143+ ],
1144+ "textMessageStatus": 1,
1145+ "textReadTimestamp": new Date(),
1146+ "timestamp": new Date()
1147+ }
1148+
1149+ var image = findChild(mmsDelegate, "imageAttachment")
1150+ verify(image != null)
1151+ waitForRendering(image)
1152+ compare(image.source, "image://theme/image-missing")
1153+ }
1154+ }
1155+
1156+ UbuntuTestCase {
1157+ id: mmsVideoDelegateTestCase
1158+ name: 'mmsVideoDelegateTestCase'
1159+
1160+ when: windowShown
1161+
1162+
1163+ function test_load_video() {
1164+ mmsDelegate.messageData = {
1165+ "newEvent": false,
1166+ "participants": [],
1167+ "sender": {"alias": ""},
1168+ "senderId": "self",
1169+ "textMessage": "Message Delegate QML Test",
1170+ "textMessageAttachments": [
1171+ {
1172+ "contentType": "video/mp4",
1173+ "filePath": Qt.resolvedUrl("./data/sample.mp4")
1174+ }
1175+ ],
1176+ "textMessageStatus": 1,
1177+ "textReadTimestamp": new Date(),
1178+ "timestamp": new Date()
1179+ }
1180+
1181+ var video = findChild(mmsDelegate, "videoAttachment")
1182+ verify(video != null)
1183+ waitForRendering(video)
1184+ verify(video.source != "image://theme/image-missing")
1185+
1186+ var icon = findChild(mmsDelegate, "playbackStartIcon")
1187+ verify(icon != null)
1188+ waitForRendering(icon)
1189+ verify(icon.visible)
1190+ }
1191+
1192+ function test_load_invalid_path() {
1193+ skip("image://thumbnailer is not reporting an error for wrong file path")
1194+ mmsDelegate.messageData = {
1195+ "newEvent": false,
1196+ "participants": [],
1197+ "sender": {"alias": ""},
1198+ "senderId": "self",
1199+ "textMessage": "Message Delegate QML Test",
1200+ "textMessageAttachments": [
1201+ {
1202+ "contentType": "video/mp4",
1203+ "filePath": "/wrong/path/file.mp4"
1204+ }
1205+ ],
1206+ "textMessageStatus": 1,
1207+ "textReadTimestamp": new Date(),
1208+ "timestamp": new Date()
1209+ }
1210+
1211+ var video = findChild(mmsDelegate, "videoAttachment")
1212+ verify(video != null)
1213+ waitForRendering(video)
1214+ compare(video.source, "image://theme/image-missing")
1215+ }
1216+ }
1217+}
1218
1219=== added file 'tests/qml/tst_PreviewerImage.qml'
1220--- tests/qml/tst_PreviewerImage.qml 1970-01-01 00:00:00 +0000
1221+++ tests/qml/tst_PreviewerImage.qml 2015-12-08 18:33:04 +0000
1222@@ -0,0 +1,103 @@
1223+/*
1224+ * Copyright 2015 Canonical Ltd.
1225+ *
1226+ * Authors:
1227+ * Arthur Mello <arthur.mello@canonical.com>
1228+ *
1229+ * This file is part of messaging-app.
1230+ *
1231+ * messaging-app is free software; you can redistribute it and/or modify
1232+ * it under the terms of the GNU General Public License as published by
1233+ * the Free Software Foundation; version 3.
1234+ *
1235+ * messaging-app is distributed in the hope that it will be useful,
1236+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1237+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1238+ * GNU General Public License for more details.
1239+ *
1240+ * You should have received a copy of the GNU General Public License
1241+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1242+ */
1243+
1244+import QtQuick 2.2
1245+import QtTest 1.0
1246+import Ubuntu.Test 0.1
1247+
1248+import '../../src/qml/MMS'
1249+
1250+Item {
1251+ id: root
1252+
1253+ width: units.gu(40)
1254+ height: units.gu(40)
1255+
1256+ PreviewerImage {
1257+ id: previewerImage
1258+ objectName: "previewerImage"
1259+
1260+ property var application: QtObject {
1261+ property bool fullscreen: false
1262+ }
1263+
1264+ anchors.fill: parent
1265+
1266+ attachment: {
1267+ "contentType": "image/png",
1268+ "filePath": Qt.resolvedUrl("./data/sample.png")
1269+ }
1270+ }
1271+
1272+ UbuntuTestCase {
1273+ id: previewerImageTestCase
1274+ name: 'peviewerImageTestCase'
1275+
1276+ when: windowShown
1277+
1278+ function test_load_image() {
1279+ var activityIndicator = findChild(previewerImage, "imageActivityIndicator")
1280+ verify(activityIndicator != null)
1281+ tryCompare(activityIndicator, "visible", false)
1282+
1283+ var thumbnail = findChild(previewerImage, "thumbnailImage")
1284+ verify(thumbnail != null)
1285+ tryCompare(thumbnail, "opacity", 1.0)
1286+
1287+ var highRes = findChild(previewerImage, "highResolutionImage")
1288+ verify(highRes != null)
1289+ compare(highRes.source, "")
1290+ }
1291+
1292+ function test_zoom_in_out() {
1293+ var activityIndicator = findChild(previewerImage, "imageActivityIndicator")
1294+ verify(activityIndicator != null)
1295+ tryCompare(activityIndicator, "visible", false)
1296+
1297+ var thumbnail = findChild(previewerImage, "thumbnailImage")
1298+ verify(thumbnail != null)
1299+ tryCompare(thumbnail, "opacity", 1.0)
1300+
1301+ var highRes = findChild(previewerImage, "highResolutionImage")
1302+ verify(highRes != null)
1303+ compare(highRes.source, "")
1304+
1305+ mouseDoubleClick(thumbnail)
1306+ verify(highRes.source !== "")
1307+
1308+ mouseDoubleClick(thumbnail)
1309+ compare(highRes.source, "")
1310+ }
1311+
1312+ function test_toggle_fullscreen() {
1313+ var activityIndicator = findChild(previewerImage, "imageActivityIndicator")
1314+ verify(activityIndicator != null)
1315+ tryCompare(activityIndicator, "visible", false)
1316+
1317+ var thumbnail = findChild(previewerImage, "thumbnailImage")
1318+ verify(thumbnail != null)
1319+
1320+ verify(previewerImage.application.fullscreen)
1321+ mouseClick(thumbnail)
1322+ tryCompare(previewerImage.application, "fullscreen", false)
1323+ }
1324+ }
1325+}
1326
1327=== added file 'tests/qml/tst_PreviewerVideo.qml'
1328--- tests/qml/tst_PreviewerVideo.qml 1970-01-01 00:00:00 +0000
1329+++ tests/qml/tst_PreviewerVideo.qml 2015-12-08 18:33:04 +0000
1330@@ -0,0 +1,87 @@
1331+/*
1332+ * Copyright 2015 Canonical Ltd.
1333+ *
1334+ * Authors:
1335+ * Arthur Mello <arthur.mello@canonical.com>
1336+ *
1337+ * This file is part of messaging-app.
1338+ *
1339+ * messaging-app is free software; you can redistribute it and/or modify
1340+ * it under the terms of the GNU General Public License as published by
1341+ * the Free Software Foundation; version 3.
1342+ *
1343+ * messaging-app is distributed in the hope that it will be useful,
1344+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1345+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1346+ * GNU General Public License for more details.
1347+ *
1348+ * You should have received a copy of the GNU General Public License
1349+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1350+ */
1351+
1352+import QtQuick 2.2
1353+import QtTest 1.0
1354+import Ubuntu.Content 0.1
1355+import Ubuntu.Test 0.1
1356+
1357+import '../../src/qml/MMS'
1358+
1359+Item {
1360+ id: root
1361+
1362+ width: units.gu(40)
1363+ height: units.gu(40)
1364+
1365+ PreviewerVideo {
1366+ id: previewerVideo
1367+ objectName: "previewerVideo"
1368+
1369+ property var application: QtObject {
1370+ property bool fullscreen: false
1371+ }
1372+
1373+ function getContentType(filePath) {
1374+ return ContentType.Videos
1375+ }
1376+
1377+ anchors.fill: parent
1378+
1379+ attachment: {
1380+ "contentType": "video/mp4",
1381+ "filePath": Qt.resolvedUrl("./data/sample.mp4")
1382+ }
1383+ }
1384+
1385+ UbuntuTestCase {
1386+ id: previewerVideoTestCase
1387+ name: 'peviewerVideoTestCase'
1388+
1389+ when: windowShown
1390+
1391+ function test_load_video() {
1392+ var videoPlayer = findChild(previewerVideo, "videoPlayer")
1393+ verify(videoPlayer != null)
1394+ tryCompare(videoPlayer, "visible", true)
1395+
1396+ var toolbar = findChild(previewerVideo, "toolbar")
1397+ verify(toolbar != null)
1398+ tryCompare(toolbar, "collapsed", true)
1399+ }
1400+
1401+ function test_toggle_toolbar() {
1402+ var videoPlayer = findChild(previewerVideo, "videoPlayer")
1403+ verify(videoPlayer != null)
1404+ tryCompare(videoPlayer, "visible", true)
1405+
1406+ var toolbar = findChild(previewerVideo, "toolbar")
1407+ verify(toolbar != null)
1408+ tryCompare(toolbar, "collapsed", true)
1409+
1410+ mouseClick(videoPlayer)
1411+ tryCompare(toolbar, "collapsed", false)
1412+
1413+ mouseClick(videoPlayer)
1414+ tryCompare(toolbar, "collapsed", true)
1415+ }
1416+ }
1417+}
1418
1419=== added file 'tests/qml/tst_QmlTests.cpp'
1420--- tests/qml/tst_QmlTests.cpp 1970-01-01 00:00:00 +0000
1421+++ tests/qml/tst_QmlTests.cpp 2015-12-08 18:33:04 +0000
1422@@ -0,0 +1,61 @@
1423+/*
1424+ * Copyright (C) 2015 Canonical, Ltd.
1425+ *
1426+ * Authors:
1427+ * Arthur Mello <arthur.mello@canonical.com>
1428+ *
1429+ * This file is part of messaging-app.
1430+ *
1431+ * messaging-app is free software; you can redistribute it and/or modify
1432+ * it under the terms of the GNU General Public License as published by
1433+ * the Free Software Foundation; version 3.
1434+ *
1435+ * messaging-app is distributed in the hope that it will be useful,
1436+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1437+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1438+ * GNU General Public License for more details.
1439+ *
1440+ * You should have received a copy of the GNU General Public License
1441+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1442+ */
1443+
1444+// Qt
1445+#include <QtQuickTest/QtQuickTest>
1446+#include <QtQml/QtQml>
1447+
1448+// local
1449+#include "fileoperations.h"
1450+
1451+class TestContext : public QObject
1452+{
1453+ Q_OBJECT
1454+
1455+public:
1456+ explicit TestContext(QObject* parent=0)
1457+ : QObject(parent)
1458+ {}
1459+};
1460+
1461+static QObject* TestContext_singleton_factory(QQmlEngine* engine, QJSEngine* scriptEngine)
1462+{
1463+ Q_UNUSED(engine);
1464+ Q_UNUSED(scriptEngine);
1465+ return new TestContext();
1466+}
1467+
1468+static QObject* FileOperations_singleton_factory(QQmlEngine* engine, QJSEngine* scriptEngine)
1469+{
1470+ Q_UNUSED(engine);
1471+ Q_UNUSED(scriptEngine);
1472+ return new FileOperations();
1473+}
1474+
1475+int main(int argc, char** argv)
1476+{
1477+ qmlRegisterSingletonType<FileOperations>("messagingapp.private", 0, 1, "FileOperations", FileOperations_singleton_factory);
1478+ qmlRegisterSingletonType<TestContext>("messagingtest.private", 0, 1, "TestContext", TestContext_singleton_factory);
1479+
1480+ return quick_test_main(argc, argv, "QmlTests", 0);
1481+}
1482+
1483+#include "tst_QmlTests.moc"

Subscribers

People subscribed via source and target branches