on xenial help sign in
better handling of sizing
83db16eNick Dedekind
qml/Components/MediaServices/MediaServices.qml+40−30
@@ -24,6 +24,7 @@ FocusScope {
24 property string context: ""
24 property string context: ""
25 property list<Action> actions
25 property list<Action> actions
26 property Item rootItem: QuickUtils.rootItem(root)
26 property Item rootItem: QuickUtils.rootItem(root)
27+ property var maximumEmbeddedHeight
27
28
28 property alias header: headerContent.item
29 property alias header: headerContent.item
29 property alias content: contentLoader.item
30 property alias content: contentLoader.item
@@ -32,39 +33,47 @@ FocusScope {
32
33
33 signal close();
34 signal close();
34
35
35− implicitHeight: {
36− if (fullscreen && parent) {
37− return parent.height;
38− }
39− return content ? content.implicitHeight : parent.height
40− }
41−
42 onFullscreenChanged: {
36 onFullscreenChanged: {
43 if (!fullscreen) rotationAction.checked = false;
37 if (!fullscreen) rotationAction.checked = false;
44 }
38 }
45
39
46 OrientationHelper {
40 OrientationHelper {
47 id: orientationHelper
41 id: orientationHelper
48− automaticOrientation: fullscreen && !rotationAction.checked
42+ automaticOrientation: fullscreen
49−
43+
44+ StateGroup {
45+ id: orientationState
46+
50− states: [
47+ states: [
51− State {
48+ State {
52− name: "portrait"
49+ name: "portrait"
53− when: !orientationHelper.automaticOrientation && !rotationAction.checked
50+ when: !rotationAction.checked
54− PropertyChanges {
51+ },
55− target: orientationHelper
52+ State {
56− orientationAngle: 0
53+ name: "landscape"
54+ when: rotationAction.checked
57 }
55 }
58− },
56+ ]
59− State {
57+
58+ transitions: [
59+ Transition {
60− name: "landscape"
60+ to: "landscape"
61+ SequentialAnimation {
61− when: !orientationHelper.automaticOrientation && rotationAction.checked
62+ PropertyAction { target: orientationHelper; property: "automaticOrientation"; value: false }
62− PropertyChanges {
63− target: orientationHelper
63+ PropertyAction { target: orientationHelper; property: "orientationAngle"; value: 90 }
64− orientationAngle: orientationHelper.orientationAngle == 270 ? 270 : 90
64+ PropertyAction { target: orientationHelper; property: "automaticOrientation"; value: false }
65+ }
66+ },
67+ Transition {
68+ to: "portrait"
69+ SequentialAnimation {
70+ PropertyAction { target: orientationHelper; property: "automaticOrientation"; value: false }
71+ PropertyAction { target: orientationHelper; property: "orientationAngle"; value: 0 }
72+ PropertyAction { target: orientationHelper; property: "automaticOrientation"; value: fullscreen }
73+ }
65 }
74 }
66− }
75+ ]
67− ]
76+ }
68
77
69 Loader {
78 Loader {
70 id: contentLoader
79 id: contentLoader
@@ -91,9 +100,9 @@ FocusScope {
91
100
92 width: orientationHelper.width
101 width: orientationHelper.width
93 height: orientationHelper.height
102 height: orientationHelper.height
94−
103+ maximumEmbeddedHeight: root.maximumEmbeddedHeight
95 fixedHeight: fullscreen
104 fixedHeight: fullscreen
96− orientation: orientationHelper.state == "portrait" ? Qt.PortraitOrientation : Qt.LandscapeOrientation
105+ orientation: orientationState.state == "landscape" ? Qt.LandscapeOrientation : Qt.PortraitOrientation
97
106
98 screenshot: {
107 screenshot: {
99 var screenshot = root.sourceData["screenshot"];
108 var screenshot = root.sourceData["screenshot"];
@@ -323,21 +332,22 @@ FocusScope {
323 State {
332 State {
324 name: "minimized"
333 name: "minimized"
325 when: !priv.fullscreen
334 when: !priv.fullscreen
335+ PropertyChanges { target: root; implicitHeight: content ? content.implicitHeight : 0; }
326 },
336 },
327 State {
337 State {
328 name: "fullscreen"
338 name: "fullscreen"
329 when: priv.fullscreen
339 when: priv.fullscreen
330− ParentChange { target: root; parent: rootItem; x: 0; y: 0; width: parent.width; height: parent.height }
340+ ParentChange { target: root; parent: rootItem; x: 0; y: 0; width: parent.width; }
341+ PropertyChanges { target: root; implicitHeight: root.parent ? root.parent.height : 0; }
331 PropertyChanges { target: fullscreenAction; iconName: "view-restore" }
342 PropertyChanges { target: fullscreenAction; iconName: "view-restore" }
332 }
343 }
333 ]
344 ]
334
345
335 transitions: Transition {
346 transitions: Transition {
336 ParentAnimation {
347 ParentAnimation {
337− UbuntuNumberAnimation { properties: "x,y,width,height"; duration: UbuntuAnimation.FastDuration }
348+ UbuntuNumberAnimation { properties: "x,y,width,implicitHeight"; duration: UbuntuAnimation.FastDuration }
338 }
349 }
339 }
350 }
340−
341 }
351 }
342
352
343 QtObject {
353 QtObject {
qml/Components/MediaServices/VideoPlayer.qml+17−2
@@ -27,6 +27,7 @@ Item {
27 property alias mediaPlayer: videoOutput.source
27 property alias mediaPlayer: videoOutput.source
28 property int orientation: Qt.PortraitOrientation
28 property int orientation: Qt.PortraitOrientation
29 property bool fixedHeight: false
29 property bool fixedHeight: false
30+ property var maximumEmbeddedHeight
30
31
31 implicitHeight: {
32 implicitHeight: {
32 if (parent && orientation == Qt.LandscapeOrientation) {
33 if (parent && orientation == Qt.LandscapeOrientation) {
@@ -45,7 +46,17 @@ Item {
45 right: parent.right
46 right: parent.right
46 verticalCenter: parent.verticalCenter
47 verticalCenter: parent.verticalCenter
47 }
48 }
49+ height: {
48− height: root.orientation == Qt.LandscapeOrientation || fixedHeight ? root.height : Math.max(image.height, videoOutput.height);
50+ if (root.orientation == Qt.LandscapeOrientation || fixedHeight) {
51+ return root.height;
52+ }
53+ var proposedHeight = videoOutput.height;
54+ if (maximumEmbeddedHeight !== undefined && maximumEmbeddedHeight < proposedHeight) {
55+ return maximumEmbeddedHeight;
56+ }
57+ return proposedHeight;
58+ }
59+ clip: image.height > videoOutput.height
49
60
50 LazyImage {
61 LazyImage {
51 id: image
62 id: image
@@ -69,9 +80,13 @@ Item {
69 if (fixedHeight) {
80 if (fixedHeight) {
70 return root.height;
81 return root.height;
71 }
82 }
72− return mediaPlayer && mediaPlayer.metaData.resolution !== undefined ?
83+ var proposedHeight = mediaPlayer && mediaPlayer.metaData.resolution !== undefined ?
73 (mediaPlayer.metaData.resolution.height / mediaPlayer.metaData.resolution.width ) * width :
84 (mediaPlayer.metaData.resolution.height / mediaPlayer.metaData.resolution.width ) * width :
74 image.height;
85 image.height;
86+ if (maximumEmbeddedHeight !== undefined && maximumEmbeddedHeight < proposedHeight) {
87+ return maximumEmbeddedHeight;
88+ }
89+ return proposedHeight;
75 }
90 }
76
91
77 source: mediaPlayer
92 source: mediaPlayer
qml/Dash/Previews/PreviewInlineVideo.qml+1
@@ -41,6 +41,7 @@ PreviewWidget {
41 context: "video"
41 context: "video"
42 sourceData: root.isCurrentPreview ? widgetData : undefined
42 sourceData: root.isCurrentPreview ? widgetData : undefined
43 fullscreen: false
43 fullscreen: false
44+ maximumEmbeddedHeight: rootItem.height / 2
44
45
45 onClose: fullscreen = false
46 onClose: fullscreen = false
46
47
tests/mocks/QtMultimedia/mediaplayer.cpp+8
@@ -67,6 +67,7 @@ MediaPlayer::MediaPlayer(QObject* parent)
67 disconnect(dataSource, &MediaDataSource::durationChanged, this, &MediaPlayer::durationChanged);
67 disconnect(dataSource, &MediaDataSource::durationChanged, this, &MediaPlayer::durationChanged);
68 disconnect(dataSource, &MediaDataSource::seekableChanged, this, &MediaPlayer::seekableChanged);
68 disconnect(dataSource, &MediaDataSource::seekableChanged, this, &MediaPlayer::seekableChanged);
69 disconnect(dataSource, &MediaDataSource::availabilityChanged, this, &MediaPlayer::availabilityChanged);
69 disconnect(dataSource, &MediaDataSource::availabilityChanged, this, &MediaPlayer::availabilityChanged);
70+ disconnect(dataSource, &MediaDataSource::metaDataChanged, m_metaData, &MetaDataObject::metaDataChanged);
70 });
71 });
71
72
72 connect(MediaPlayerDataController::instance(), &MediaPlayerDataController::sourceAdded,
73 connect(MediaPlayerDataController::instance(), &MediaPlayerDataController::sourceAdded,
@@ -77,6 +78,7 @@ MediaPlayer::MediaPlayer(QObject* parent)
77 connect(dataSource, &MediaDataSource::durationChanged, this, &MediaPlayer::durationChanged);
78 connect(dataSource, &MediaDataSource::durationChanged, this, &MediaPlayer::durationChanged);
78 connect(dataSource, &MediaDataSource::seekableChanged,this, &MediaPlayer::seekableChanged);
79 connect(dataSource, &MediaDataSource::seekableChanged,this, &MediaPlayer::seekableChanged);
79 connect(dataSource, &MediaDataSource::availabilityChanged,this, &MediaPlayer::availabilityChanged);
80 connect(dataSource, &MediaDataSource::availabilityChanged,this, &MediaPlayer::availabilityChanged);
81+ connect(dataSource, &MediaDataSource::metaDataChanged, m_metaData, &MetaDataObject::metaDataChanged);
80 });
82 });
81}
83}
82
84
@@ -96,6 +98,7 @@ void MediaPlayer::setSource(const QUrl &source)
96
98
97 m_position = 0;
99 m_position = 0;
98 Q_EMIT positionChanged(m_position);
100 Q_EMIT positionChanged(m_position);
101+ Q_EMIT m_metaData->metaDataChanged();
99
102
100 m_status = availability()==Available ? Loaded : InvalidMedia;
103 m_status = availability()==Available ? Loaded : InvalidMedia;
101 Q_EMIT statusChanged();
104 Q_EMIT statusChanged();
@@ -204,6 +207,11 @@ MediaPlayer::Availability MediaPlayer::availability() const
204 return Available;
207 return Available;
205}
208}
206
209
210+QObject *MediaPlayer::metaData() const
211+{
212+ return m_metaData;
213+}
214+
207
215
208MediaDataSource::MediaDataSource(QObject *parent)
216MediaDataSource::MediaDataSource(QObject *parent)
209 : QObject(parent)
217 : QObject(parent)
tests/mocks/QtMultimedia/mediaplayer.h+4−2
@@ -25,6 +25,8 @@
25#include <QHash>
25#include <QHash>
26#include <QVariant>
26#include <QVariant>
27
27
28+class MetaDataObject;
29+
28class MediaPlayer: public QObject
30class MediaPlayer: public QObject
29{
31{
30 Q_OBJECT
32 Q_OBJECT
@@ -109,7 +111,7 @@ public:
109 bool isSeekable() const;
111 bool isSeekable() const;
110 MediaPlayer::Availability availability() const;
112 MediaPlayer::Availability availability() const;
111 Status status() const { return m_status; }
113 Status status() const { return m_status; }
112− QObject *metaData() const { return m_metaData; }
114+ QObject *metaData() const;
113
115
114public Q_SLOTS:
116public Q_SLOTS:
115 void pause();
117 void pause();
@@ -139,7 +141,7 @@ private:
139 QTimer m_timer;
141 QTimer m_timer;
140 int m_position;
142 int m_position;
141 Status m_status;
143 Status m_status;
142− QObject *m_metaData;
144+ MetaDataObject *m_metaData;
143};
145};
144
146
145class MediaDataSource : public QObject
147class MediaDataSource : public QObject
tests/qmltests/Components/tst_MediaServices.qml+24
@@ -32,6 +32,11 @@ Rectangle {
32 "screenshot": Qt.resolvedUrl("../Dash/artwork/avatar.png")
32 "screenshot": Qt.resolvedUrl("../Dash/artwork/avatar.png")
33 }
33 }
34
34
35+ property var sourceData2: {
36+ "source": "file:///home/nick/Videos/test-mpeg2.ogv",
37+ "screenshot": Qt.resolvedUrl("../Dash/artwork/checkers.png")
38+ }
39+
35 MediaDataSource {
40 MediaDataSource {
36 source: root.sourceData["source"]
41 source: root.sourceData["source"]
37 duration: 60000
42 duration: 60000
@@ -41,6 +46,15 @@ Rectangle {
41 }
46 }
42 }
47 }
43
48
49+ MediaDataSource {
50+ source: root.sourceData2["source"]
51+ duration: 30000
52+ metaData: {
53+ "title" : "TEST MPEG",
54+ "resolution" : { "width": 90, "height": 240 }
55+ }
56+ }
57+
44 Item {
58 Item {
45 anchors.fill: parent
59 anchors.fill: parent
46
60
@@ -61,6 +75,7 @@ Rectangle {
61 context: "video"
75 context: "video"
62
76
63 rootItem: parent
77 rootItem: parent
78+ maximumEmbeddedHeight: undefined
64 }
79 }
65 }
80 }
66
81
@@ -99,6 +114,7 @@ Rectangle {
99 property int oldControlTimerInterval: 0;
114 property int oldControlTimerInterval: 0;
100
115
101 function init() {
116 function init() {
117+ services.sourceData = root.sourceData
102 services.context = "video";
118 services.context = "video";
103
119
104 var controlHideTimer = findInvisibleChild(services, "controlHideTimer");
120 var controlHideTimer = findInvisibleChild(services, "controlHideTimer");
@@ -110,6 +126,7 @@ Rectangle {
110 serviceCloseSpy.clear();
126 serviceCloseSpy.clear();
111 services.context = "";
127 services.context = "";
112 services.fullscreen = false;
128 services.fullscreen = false;
129+ services.maximumEmbeddedHeight = undefined;
113 tryCompareFunction(function() { return services.header ? services.header.visible : false }, false);
130 tryCompareFunction(function() { return services.header ? services.header.visible : false }, false);
114 tryCompareFunction(function() { return services.footer ? services.footer.visible : false }, false);
131 tryCompareFunction(function() { return services.footer ? services.footer.visible : false }, false);
115
132
@@ -200,5 +217,12 @@ Rectangle {
200 tap(navigationButton);
217 tap(navigationButton);
201 compare(serviceCloseSpy.count, 1, "close was not called");
218 compare(serviceCloseSpy.count, 1, "close was not called");
202 }
219 }
220+
221+ function test_maximumVideoSize() {
222+ services.maximumEmbeddedHeight = root.height / 2
223+ services.sourceData = root.sourceData2
224+ verify(services.content !== null);
225+ tryCompare(services.content, "height", root.height/2);
226+ }
203 }
227 }
204}
228}