on xenial help sign in
Added tests for audio player widget
commitd13ce37d46aeebd20f80602302503eb6e74013ab authorAndrea Cimitan <andrea.cimitan@gmail.com> dateWed 29 Jan 2014, 16:12 (13 years ago) parentedb5cde
4 files changed+383−103
qml/Dash/Music/MusicPreview.qml+88−10 qml/Dash/Previews/AudioPlayer.qml+134−93 tests/qmltests/CMakeLists.txt+1 tests/qmltests/Dash/Previews/tst_AudioPlayer.qml+160
qml/Dash/Music/MusicPreview.qml+88−10
@@ -93,19 +93,14 @@ GenericPreview {
9393
9494 model: previewData.tracks
9595
96− delegate: AudioPlayer {
96+ delegate: Item {
9797 id: trackItem
9898 objectName: "trackItem" + index
9999 anchors { left: parent.left; right: parent.right }
100100 height: units.gu(5)
101+ property bool isPlayingItem: audioPlayer.playingItem == trackItem
101102
102− isPlayingItem: audioPlayer.playingItem == trackItem
103− playbackState: audioPlayer.playbackState
104− progress: audioPlayer.progress
105− title: model.title
106− length: model.length
107−
108− onPlay: {
103+ function play() {
109104 audioPlayer.stop();
110105 // Make sure we change the source, even if two items point to the same uri location
111106 audioPlayer.source = "";
@@ -114,8 +109,91 @@ GenericPreview {
114109 audioPlayer.play();
115110 }
116111
117− onPause: {
118− audioPlayer.stop()
112+ Row {
113+ id: trackRow
114+ width: parent.width
115+ spacing: units.gu(1)
116+ property int column1Width: units.gu(3)
117+ property int column2Width: width - (2 * spacing) - column1Width - column3Width
118+ property int column3Width: units.gu(4)
119+ anchors.verticalCenter: parent.verticalCenter
120+
121+ Button {
122+ objectName: "playButton"
123+ width: trackRow.column1Width
124+ height: width
125+ iconSource: audioPlayer.playbackState == Audio.PlayingState && trackItem.isPlayingItem ? "image://theme/media-playback-pause" : "image://theme/media-playback-start"
126+
127+ // Can't be "transparent" or "#00xxxxxx" as the button optimizes away the surrounding shape
128+ // FIXME when this is resolved: https://bugs.launchpad.net/ubuntu-ui-toolkit/+bug/1251685
129+ color: "#01000000"
130+
131+ onClicked: {
132+ if (trackItem.isPlayingItem) {
133+ if (audioPlayer.playbackState == Audio.PlayingState) {
134+ audioPlayer.pause();
135+ } else if (audioPlayer.playbackState == Audio.PausedState){
136+ audioPlayer.play();
137+ }
138+ } else {
139+ trackItem.play();
140+ }
141+ }
142+ }
143+
144+ Label {
145+ objectName: "trackTitleLabel"
146+ fontSize: "small"
147+ opacity: 0.9
148+ color: "white"
149+ horizontalAlignment: Text.AlignLeft
150+ anchors.verticalCenter: parent.verticalCenter
151+ width: parent.column2Width
152+ text: title
153+ style: Text.Raised
154+ styleColor: "black"
155+ elide: Text.ElideRight
156+
157+ UbuntuShape {
158+ id: progressBarFill
159+ objectName: "progressBarFill"
160+ color: UbuntuColors.orange
161+ anchors.left: progressBarImage.left
162+ anchors.right: progressBarImage.right
163+ anchors.verticalCenter: progressBarImage.verticalCenter
164+ height: units.dp(2)
165+ anchors.margins: units.dp(2)
166+ anchors.rightMargin: maxWidth - (maxWidth * audioPlayer.progress) + units.dp(2)
167+ visible: progressBarImage.visible
168+ property int maxWidth: progressBarImage.width - units.dp(4)
169+ }
170+
171+ Image {
172+ id: progressBarImage
173+ anchors { left: parent.left; top: parent.bottom; right: parent.right }
174+ height: units.dp(6)
175+ visible: audioPlayer.playbackState != Audio.StoppedState && trackItem.isPlayingItem && model.length.length > 0
176+ source: "graphics/music_progress_bg.png"
177+ }
178+ }
179+
180+ Label {
181+ id: valueLabel
182+ objectName: "timeLabel"
183+ fontSize: "small"
184+ opacity: 0.9
185+ color: "white"
186+ anchors.verticalCenter: parent.verticalCenter
187+ horizontalAlignment: Text.AlignRight
188+ width: parent.column3Width
189+ text: length
190+ style: Text.Raised
191+ styleColor: "black"
192+ }
193+ }
194+
195+ ThinDivider {
196+ anchors { left: parent.left; bottom: parent.bottom; right: parent.right }
119197 }
120198 }
121199 }
qml/Dash/Previews/AudioPlayer.qml+134−93
@@ -20,104 +20,145 @@ import Ubuntu.Components 0.1
2020import Ubuntu.Components.ListItems 0.1
2121
2222Item {
23− id: trackItem
24− implicitHeight: units.gu(5)
25−
26− property bool isPlayingItem
27− property int playbackState
28− property real progress: 0
29− property string title
30− property string length
31−
32− signal play()
33−
34− signal pause()
35−
36− Row {
37− id: trackRow
38− width: parent.width
39− spacing: units.gu(1)
40− property int column1Width: units.gu(3)
41− property int column2Width: width - (2 * spacing) - column1Width - column3Width
42− property int column3Width: units.gu(4)
43− anchors.verticalCenter: parent.verticalCenter
44−
45− Button {
46− objectName: "playButton"
47− width: trackRow.column1Width
48− height: width
49− iconSource: trackItem.playbackState == Audio.PlayingState && trackItem.isPlayingItem ? "image://theme/media-playback-pause" : "image://theme/media-playback-start"
50−
51− // Can't be "transparent" or "#00xxxxxx" as the button optimizes away the surrounding shape
52− // FIXME when this is resolved: https://bugs.launchpad.net/ubuntu-ui-toolkit/+bug/1251685
53− color: "#01000000"
54−
55− onClicked: {
56− if (trackItem.isPlayingItem) {
57− if (trackItem.playbackState == Audio.PlayingState) {
58− trackItem.pause();
59− } else if (audioPlayer.playbackState == Audio.PausedState){
60− trackItem.play();
61− }
62− } else {
63− trackItem.play();
64− }
65− }
66− }
23+ id: root
24+ property alias model: trackRepeater.model
6725
68− Label {
69− objectName: "trackTitleLabel"
70− fontSize: "small"
71− opacity: 0.9
72− color: "white"
73− horizontalAlignment: Text.AlignLeft
74− anchors.verticalCenter: parent.verticalCenter
75− width: parent.column2Width
76− text: title
77− style: Text.Raised
78− styleColor: "black"
79− elide: Text.ElideRight
80−
81− UbuntuShape {
82− id: progressBarFill
83− objectName: "progressBarFill"
84− color: UbuntuColors.orange
85− anchors.left: progressBarImage.left
86− anchors.right: progressBarImage.right
87− anchors.verticalCenter: progressBarImage.verticalCenter
88− height: units.dp(2)
89− anchors.margins: units.dp(2)
90− anchors.rightMargin: maxWidth - (maxWidth * progress) + units.dp(2)
91− visible: progressBarImage.visible
92−
93− property int maxWidth: progressBarImage.width - units.dp(4)
94− }
26+ implicitHeight: childrenRect.height
9527
96− Image {
97− id: progressBarImage
98− anchors { left: parent.left; top: parent.bottom; right: parent.right }
99− height: units.dp(6)
100− visible: trackItem.playbackState != Audio.StoppedState && trackItem.isPlayingItem && length.length > 0
101− source: "graphics/music_progress_bg.png"
102− }
103− }
28+ function stop() {
29+ audio.stop()
30+ }
31+
32+ Audio {
33+ id: audio
34+ objectName: "audio"
35+ property real progress: audio.position / audio.duration
10436
105− Label {
106− id: valueLabel
107− objectName: "timeLabel"
108− fontSize: "small"
109− opacity: 0.9
110− color: "white"
111− anchors.verticalCenter: parent.verticalCenter
112− horizontalAlignment: Text.AlignRight
113− width: parent.column3Width
114− text: length
115− style: Text.Raised
116− styleColor: "black"
37+ property Item playingItem
38+
39+ Component.onDestruction: {
40+ audio.stop();
11741 }
42+
43+ onErrorStringChanged: console.warn("Audio player error:", errorString)
11844 }
11945
120− ThinDivider {
121− anchors { left: parent.left; bottom: parent.bottom; right: parent.right }
46+ Column {
47+ anchors { left: parent.left; right: parent.right }
48+ visible: trackRepeater.count > 0
49+
50+ ThinDivider {
51+ objectName: "topDivider"
52+ anchors { left: parent.left; right: parent.right }
53+ }
54+
55+ Repeater {
56+ id: trackRepeater
57+ objectName: "trackRepeater"
58+
59+ delegate: Item {
60+ id: trackItem
61+ objectName: "trackItem" + index
62+ anchors { left: parent.left; right: parent.right }
63+ height: units.gu(5)
64+ property bool isPlayingItem: audio.playingItem == trackItem
65+
66+ function play() {
67+ audio.stop();
68+ // Make sure we change the source, even if two items point to the same uri location
69+ audio.source = "";
70+ audio.source = modelData["uri"];
71+ audio.playingItem = trackItem;
72+ audio.play();
73+ }
74+
75+ Row {
76+ id: trackRow
77+ width: parent.width
78+ spacing: units.gu(1)
79+ property int column1Width: units.gu(3)
80+ property int column2Width: width - (2 * spacing) - column1Width - column3Width
81+ property int column3Width: units.gu(4)
82+ anchors.verticalCenter: parent.verticalCenter
83+
84+ Button {
85+ objectName: "playButton"
86+ width: trackRow.column1Width
87+ height: width
88+ iconSource: audio.playbackState == Audio.PlayingState && trackItem.isPlayingItem ? "image://theme/media-playback-pause" : "image://theme/media-playback-start"
89+
90+ // Can't be "transparent" or "#00xxxxxx" as the button optimizes away the surrounding shape
91+ // FIXME when this is resolved: https://bugs.launchpad.net/ubuntu-ui-toolkit/+bug/1251685
92+ color: "#01000000"
93+
94+ onClicked: {
95+ if (trackItem.isPlayingItem) {
96+ if (audio.playbackState == Audio.PlayingState) {
97+ audio.pause();
98+ } else if (audio.playbackState == Audio.PausedState){
99+ audio.play();
100+ }
101+ } else {
102+ trackItem.play();
103+ }
104+ }
105+ }
106+
107+ Label {
108+ objectName: "trackTitleLabel"
109+ fontSize: "small"
110+ opacity: 0.9
111+ color: "white"
112+ horizontalAlignment: Text.AlignLeft
113+ anchors.verticalCenter: parent.verticalCenter
114+ width: parent.column2Width
115+ text: modelData["title"]
116+ style: Text.Raised
117+ styleColor: "black"
118+ elide: Text.ElideRight
119+
120+ UbuntuShape {
121+ id: progressBarFill
122+ objectName: "progressBarFill"
123+ color: UbuntuColors.orange
124+ anchors.left: progressBarImage.left
125+ anchors.right: progressBarImage.right
126+ anchors.verticalCenter: progressBarImage.verticalCenter
127+ height: units.dp(2)
128+ anchors.margins: units.dp(2)
129+ anchors.rightMargin: maxWidth - (maxWidth * audio.progress) + units.dp(2)
130+ visible: progressBarImage.visible
131+ property int maxWidth: progressBarImage.width - units.dp(4)
132+ }
133+
134+ Image {
135+ id: progressBarImage
136+ anchors { left: parent.left; top: parent.bottom; right: parent.right }
137+ height: units.dp(6)
138+ visible: audio.playbackState != Audio.StoppedState && trackItem.isPlayingItem && modelData["length"].length > 0
139+ source: "graphics/music_progress_bg.png"
140+ }
141+ }
142+
143+ Label {
144+ id: valueLabel
145+ objectName: "timeLabel"
146+ fontSize: "small"
147+ opacity: 0.9
148+ color: "white"
149+ anchors.verticalCenter: parent.verticalCenter
150+ horizontalAlignment: Text.AlignRight
151+ width: parent.column3Width
152+ text: modelData["length"]
153+ style: Text.Raised
154+ styleColor: "black"
155+ }
156+ }
157+
158+ ThinDivider {
159+ anchors { left: parent.left; bottom: parent.bottom; right: parent.right }
160+ }
161+ }
162+ }
122163 }
123164}
tests/qmltests/CMakeLists.txt+1
@@ -53,6 +53,7 @@ add_qml_test(Dash/Apps RunningApplicationsGrid IMPORT_PATHS ${qmltest_DEFAULT_IM
5353add_qml_test(Dash/Apps AppPreview IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
5454add_qml_test(Dash/Movie MoviePreview IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
5555add_qml_test(Dash/Music MusicPreview IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
56+add_qml_test(Dash/Previews AudioPlayer IMPORT_PATHS ${qmltest_DEFAULT_IMPORT_PATHS} ${CMAKE_BINARY_DIR}/tests/mocks)
5657add_qml_test(Greeter Lockscreen IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS}
5758 PROPERTIES ENVIRONMENT "LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/tests/mocks/libusermetrics:${CMAKE_BINARY_DIR}/tests/mocks/LightDM/full")
5859add_qml_test(Greeter Tablet IMPORT_PATHS ${CMAKE_BINARY_DIR}/plugins ${qmltest_DEFAULT_IMPORT_PATHS}
tests/qmltests/Dash/Previews/tst_AudioPlayer.qmlnew file+160
@@ -0,0 +1,160 @@
1+/*
2+ * Copyright 2014 Canonical Ltd.
3+ *
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.0
18+import QtTest 1.0
19+import Ubuntu.Components 0.1
20+import "../../../../qml/Dash/Previews"
21+import Unity.Test 0.1 as UT
22+import QtMultimedia 5.0
23+
24+Rectangle {
25+ id: root
26+ width: units.gu(60)
27+ height: units.gu(80)
28+ color: "lightgrey"
29+
30+ property var tracksModel0: [
31+ ]
32+
33+ property var tracksModel1: [
34+ { title: "Some track name", length: "0:30", uri: "../../tests/qmltests/Dash/Music/data/testsound1.ogg" }
35+ ]
36+
37+ property var tracksModel2: [
38+ { title: "Some track name", length: "0:30", uri: "../../tests/qmltests/Dash/Music/data/testsound1.ogg" },
39+ { title: "Some other track name", length: "1:23", uri: "../../tests/qmltests/Dash/Music/data/testsound2.ogg" },
40+ { title: "And another one", length: "123:45", uri: "../../tests/qmltests/Dash/Music/data/testsound3.ogg" }
41+ ]
42+
43+ AudioPlayer {
44+ id: audioPlayer
45+ anchors.fill: parent
46+ model: tracksModel0
47+ }
48+
49+ UT.UnityTestCase {
50+ name: "AudioPlayerTest"
51+ when: windowShown
52+
53+ function init() {
54+ waitForRendering(audioPlayer);
55+ }
56+
57+ function test_tracks_data() {
58+ return [
59+ {tag: "0 tracks", tracksModel: tracksModel0, dividerVisible: false},
60+ {tag: "1 track", tracksModel: tracksModel1, dividerVisible: true},
61+ {tag: "4 track", tracksModel: tracksModel2, dividerVisible: true}
62+ ];
63+ }
64+
65+ function test_tracks(data) {
66+ audioPlayer.model = data.tracksModel;
67+ waitForRendering(audioPlayer);
68+
69+ var trackRepeater = findChild(audioPlayer, "trackRepeater");
70+ compare(trackRepeater.count, data.tracksModel.length)
71+
72+ var topDivider = findChild(audioPlayer, "topDivider");
73+ compare(topDivider.visible, data.dividerVisible);
74+
75+ for (var i = 0; i < data.tracksModel.count; ++i) {
76+ var trackItem = findChild(audioPlayer, "trackItem" + i);
77+ var titleLabel = findChild(trackItem, "trackTitleLabel");
78+ compare(titleLabel.text, data.tracksModel[i]["title"])
79+ var timeLabel = findChild(trackItem, "timeLabel");
80+ compare(timeLabel.text, data.tracksModel[i]["length"])
81+ }
82+ }
83+
84+ function checkPlayerUri(index) {
85+ var modelFilename = audioPlayer.model[index]["uri"].replace(/^.*[\\\/]/, '');
86+ var playerFilename = findInvisibleChild(audioPlayer, "audio").source.toString().replace(/^.*[\\\/]/, '');
87+
88+ compare(modelFilename, playerFilename, "Player source is not set correctly.");
89+ }
90+
91+ function test_playback() {
92+ audioPlayer.model = tracksModel2;
93+ waitForRendering(audioPlayer);
94+
95+ var track0Item = findChild(audioPlayer, "trackItem0");
96+ var track1Item = findChild(audioPlayer, "trackItem1");
97+ var track2Item = findChild(audioPlayer, "trackItem2");
98+
99+ var track0ProgressBar = findChild(track0Item, "progressBarFill");
100+ var track1ProgressBar = findChild(track1Item, "progressBarFill");
101+ var track2ProgressBar = findChild(track2Item, "progressBarFill");
102+
103+ var track0PlayButton = findChild(track0Item, "playButton");
104+ var track1PlayButton = findChild(track1Item, "playButton");
105+ var track2PlayButton = findChild(track2Item, "playButton");
106+
107+ var audio = findInvisibleChild(audioPlayer, "audio");
108+
109+ // All progress bars must be hidden in the beginning
110+ compare(track0ProgressBar.visible, false);
111+ compare(track1ProgressBar.visible, false);
112+ compare(track2ProgressBar.visible, false);
113+
114+ // Playing track 0 should make progress bar 0 visible
115+ mouseClick(track0PlayButton, track0PlayButton.width / 2, track0PlayButton.height / 2);
116+
117+ tryCompare(audio, "playbackState", Audio.PlayingState);
118+ checkPlayerUri(0);
119+
120+ tryCompare(track0ProgressBar, "visible", true);
121+ tryCompare(track1ProgressBar, "visible", false);
122+ tryCompare(track2ProgressBar, "visible", false);
123+
124+ // Clicking the button again should pause it. The progress bar should stay visible
125+ mouseClick(track0PlayButton, track0PlayButton.width / 2, track0PlayButton.height / 2);
126+ tryCompare(audio, "playbackState", Audio.PausedState);
127+ checkPlayerUri(0);
128+ tryCompare(track0ProgressBar, "visible", true);
129+
130+ // Continue playback
131+ mouseClick(track0PlayButton, track0PlayButton.width / 2, track0PlayButton.height / 2);
132+ tryCompare(audio, "playbackState", Audio.PlayingState);
133+ checkPlayerUri(0);
134+
135+ // Playing track 1 should make progress bar 1 visible and hide progress bar 0 again
136+ mouseClick(track1PlayButton, track1PlayButton.width / 2, track1PlayButton.height / 2);
137+
138+ tryCompare(audio, "playbackState", Audio.PlayingState);
139+ checkPlayerUri(1);
140+
141+ tryCompare(track0ProgressBar, "visible", false);
142+ tryCompare(track1ProgressBar, "visible", true);
143+ tryCompare(track2ProgressBar, "visible", false);
144+
145+ // Playing track 2 should make progress bar 1 visible and hide progress bar 0 again
146+ mouseClick(track2PlayButton, track2PlayButton.width / 2, track2PlayButton.height / 2);
147+
148+ tryCompare(audio, "playbackState", Audio.PlayingState);
149+ checkPlayerUri(2);
150+
151+ tryCompare(track0ProgressBar, "visible", false);
152+ tryCompare(track1ProgressBar, "visible", false);
153+ tryCompare(track2ProgressBar, "visible", true);
154+
155+ // Calling stop() should make all players shut up!
156+ audioPlayer.stop()
157+ tryCompare(audio, "playbackState", Audio.StoppedState);
158+ }
159+ }
160+}