Merge lp:~ahayzen/music-app/mediaplayer-simplify into lp:music-app/trusty
- mediaplayer-simplify
- Merge into trusty
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Andrew Hayzen | ||||
Approved revision: | 324 | ||||
Merged at revision: | 369 | ||||
Proposed branch: | lp:~ahayzen/music-app/mediaplayer-simplify | ||||
Merge into: | lp:music-app/trusty | ||||
Diff against target: |
1531 lines (+397/-453) 14 files modified
LibraryListModel.qml (+2/-0) MusicAlbums.qml (+1/-0) MusicNowPlaying.qml (+20/-15) MusicPlaylists.qml (+0/-7) MusicStart.qml (+1/-0) MusicToolbar.qml (+50/-71) MusicTracks.qml (+0/-5) Player.qml (+196/-0) common/AlbumsSheet.qml (+0/-4) common/BlurredBackground.qml (+3/-1) music-app.qml (+61/-294) tests/autopilot/music_app/emulators.py (+3/-0) tests/autopilot/music_app/tests/__init__.py (+4/-0) tests/autopilot/music_app/tests/test_music.py (+56/-56) |
||||
To merge this branch: | bzr merge lp:~ahayzen/music-app/mediaplayer-simplify | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Victor Thompson | Approve | ||
Ubuntu Phone Apps Jenkins Bot | continuous-integration | Approve | |
Nicholas Skaggs (community) | Approve | ||
Review via email:
|
Commit message
* Make it easier to change shuffle/repeat
* Move MediaPlayer into its own file
* Simplify bindings to MediaPlayer by using Connections
Description of the change
I know we prefer to write new features before refactoring code.
However when developing the keyboard shortcuts I noticed how difficult it had become to, for example, toggle shuffle. The code from the keyboard shortcut would have to:
* Update the Settings
* Update the global variable
* Find any UI items (eg in the toolbar) and toggle them
The following merge moves the MediaPlayer component into its own file, I have then removed the signals and code that talks to 'external' components, so this file should only access the MediaPlayer, trackQueue and Settings. Any 'external' components use Connections to 'listen' for changes in the MediaPlayer.
This has resulted in making it easier to manage, for example toggling shuffle now just requires
player.shuffle = !player.shuffle
Furthermore this simplifies loads more code and makes things easier to read/find.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
- 304. By Andrew Hayzen
-
* Fix autopilot
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:304
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 305. By Andrew Hayzen
-
* Fix for autopilot
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:305
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 306. By Andrew Hayzen
-
* Merge of trunk
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:306
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Nicholas Skaggs (nskaggs) wrote : | # |
Seems you found an issue with libautopilot-qt; can you link the bug here Andrew?
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Nicholas Skaggs (nskaggs) wrote : | # |
Waiting for https:/
- 307. By Andrew Hayzen
-
* Empty commit
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:307
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 308. By Andrew Hayzen
-
* Merge of trunk
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:308
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 309. By Andrew Hayzen
-
* Fixes for trackQueue empty
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:309
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 310. By Andrew Hayzen
-
* Fix for labels
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:310
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Victor Thompson (vthompson) wrote : | # |
Couldn't you just put the MediaPlayer in an Item and have properties defined under the item? That's the way the Qt documentation lists an example [1]. This is also how many of the Ubuntu SDK items are constructed and I can imagine it's probably the preferred way of creating custom components. You can alias the MediaPlayers properties and define signals for play()/pause/etc.
[1] http://
[2] http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:310
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 311. By Andrew Hayzen
-
* Merge of trunk
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:311
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:311
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Nicholas Skaggs (nskaggs) wrote : | # |
Are we still trying to merge this, or going a different way now?
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Andrew Hayzen (ahayzen) wrote : | # |
Think i'm gonna modify it to work within the limitations found in autopilot.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:311
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Nicholas Skaggs (nskaggs) wrote : | # |
I've lost the bug this was linked to, do you have it handy?
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Nicholas Skaggs (nskaggs) wrote : | # |
For my sanity :-) https:/
- 312. By Andrew Hayzen
-
* Merge of trunk
- 313. By Andrew Hayzen
-
* Fixes for currentIndex changes
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:313
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:313
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Nicholas Skaggs (nskaggs) wrote : | # |
The last bits of fixes for the autopilot bug affecting this should land by midweek.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:313
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild:
http://
- 314. By Andrew Hayzen
-
* Merge of trunk
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:314
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 315. By Andrew Hayzen
-
* Embed MediaPlayer inside Item and use alias to access properties
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:315
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 316. By Andrew Hayzen
-
* Add Player.qml to cmake
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:316
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:313
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Nicholas Skaggs (nskaggs) wrote : | # |
In my cmake wisdom, I think we can simplify how the qml files are specified; this should work;
file(GLOB SRC_FILES
RELATIVE ${CMAKE_
*.qml *.js *.png *.json)
install(FILES ${SRC_FILES} DESTINATION ${DATA_DIR})
Add the *.filetype for whatever is needed
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:313
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 317. By Andrew Hayzen
-
* Merge of trunk
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:317
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Victor Thompson (vthompson) wrote : | # |
Doing some initial testing on the Desktop (I'll try to do more on the phone later). It seems as through removing items from the queue is causing some item dividers to be left on the screen (see attached). Otherwise, functionally, I think things are in place. http://
- 318. By Andrew Hayzen
-
* Fix for currentIndex not referenced correctly
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Andrew Hayzen (ahayzen) wrote : | # |
Good catch I had missed a conversion of one of the properties in the removal function, please retest :)
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:318
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Nicholas Skaggs (nskaggs) wrote : | # |
This branch needs to merge for this to work. It was approved and readied a bit ago, but they seemed to have backed off on it:
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Nicholas Skaggs (nskaggs) wrote : | # |
Per thomi;
<thomi> balloons: it changes the order of objects exported by select_many, and several test suites rely (incorrectly) on that order
<thomi> so we cannot release it until everyone updates their tests
* balloons facepalms
<thomi> we're planning on building it into a PPA, so people can update their suites more easily
<thomi> ... we're still committed to getting it out
With that info, we need to decide what we're going to do with this and how to land it
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Nicholas Skaggs (nskaggs) wrote : | # |
My 2 cents, fyi, I would push for us to merge this if everyone is ready, and add a skip for the test. ::shocked?:: :-) We'll manually verify this feature before release and unskip the test once the new version of AP lands. We'll need to reference the bug and make sure we follow it.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Andrew Hayzen (ahayzen) wrote : | # |
Do we have a timescale for this conversion to take place? eg days, weeks, months? As I feel this would affect our decision.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Nicholas Skaggs (nskaggs) wrote : | # |
No ETA at this point; and I hesitate to give one since it's been stretched out so much. That said, the AP team is actively trying to land this but they are depending on others to clean up there tests so they don't experience breakage. If this can sit for 2 more weeks or so then it's an option. I'm assuming you wish to land it sooner rather than later and I don't like hings sitting out of trunk for so long; will this continue to cause re-work to rebase to trunk?
- 319. By Andrew Hayzen
-
* Fix for missed case of nextSong, stopSong conversion
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:319
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 320. By Andrew Hayzen
-
* Remove use of key-value array in player
- 321. By Andrew Hayzen
-
* Merge of trunk
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:321
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 322. By Andrew Hayzen
-
* Fixed missed cases
- 323. By Andrew Hayzen
-
* Fix for autopilot
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Andrew Hayzen (ahayzen) wrote : | # |
OK after discussions with Victor, we have decided to split the currentMeta dictionary into its separate properties (eg currentMetaTitle) so that it will pass the autopilot tests. Once the autopilot fixes land this can then be reinvestigated to whether it is better to have them as split or together.
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:323
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 324. By Andrew Hayzen
-
* Fix for autopilot
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
PASSED: Continuous integration, rev:324
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Victor Thompson (vthompson) wrote : | # |
Approved. I'm glad we could resolve this in an efficient manner. Thanks for all the work here Andrew and Nicholas!
Preview Diff
1 | === modified file 'LibraryListModel.qml' |
2 | --- LibraryListModel.qml 2014-01-30 19:54:41 +0000 |
3 | +++ LibraryListModel.qml 2014-03-07 16:40:44 +0000 |
4 | @@ -87,6 +87,8 @@ |
5 | |
6 | function indexOf(file) |
7 | { |
8 | + file = file.toString(); |
9 | + |
10 | if (file.indexOf("file://") == 0) |
11 | { |
12 | file = file.slice(7, file.length) |
13 | |
14 | === modified file 'MusicAlbums.qml' |
15 | --- MusicAlbums.qml 2014-01-16 19:22:52 +0000 |
16 | +++ MusicAlbums.qml 2014-03-07 16:40:44 +0000 |
17 | @@ -133,6 +133,7 @@ |
18 | } |
19 | onClicked: { |
20 | albumTracksModel.filterAlbumTracks(album) |
21 | + |
22 | songsSheet.line1 = artist |
23 | songsSheet.line2 = album |
24 | songsSheet.isAlbum = true |
25 | |
26 | === modified file 'MusicNowPlaying.qml' |
27 | --- MusicNowPlaying.qml 2014-02-22 22:12:21 +0000 |
28 | +++ MusicNowPlaying.qml 2014-03-07 16:40:44 +0000 |
29 | @@ -65,10 +65,25 @@ |
30 | } |
31 | |
32 | Component.onCompleted: { |
33 | - onPlayingTrackChange.connect(updateCurrentIndex) |
34 | onToolbarShownChanged.connect(jumpToCurrent) |
35 | } |
36 | |
37 | + Connections { |
38 | + target: player |
39 | + onCurrentIndexChanged: { |
40 | + if (player.source === "") { |
41 | + return; |
42 | + } |
43 | + |
44 | + // Collapse currently expanded track and the new current |
45 | + collapseExpand(queuelist.currentIndex); |
46 | + queuelist.currentIndex = player.currentIndex; |
47 | + collapseExpand(queuelist.currentIndex); |
48 | + |
49 | + customdebug("MusicQueue update currentIndex: " + player.source); |
50 | + } |
51 | + } |
52 | + |
53 | function jumpToCurrent(shown, currentPage, currentTab) |
54 | { |
55 | // If the toolbar is shown, the page is now playing and snaptrack is enabled |
56 | @@ -79,16 +94,6 @@ |
57 | } |
58 | } |
59 | |
60 | - function updateCurrentIndex(file) |
61 | - { |
62 | - // Collapse currently expanded track and the new current |
63 | - collapseExpand(queuelist.currentIndex); |
64 | - queuelist.currentIndex = currentIndex; |
65 | - collapseExpand(queuelist.currentIndex); |
66 | - |
67 | - customdebug("MusicQueue update currentIndex: " + file); |
68 | - } |
69 | - |
70 | ListView { |
71 | id: queuelist |
72 | objectName: "queuelist" |
73 | @@ -469,16 +474,16 @@ |
74 | if (queuelist.count > 1) |
75 | { |
76 | // Next song and only play if currently playing |
77 | - nextSong(isPlaying); |
78 | + player.nextSong(player.isPlaying); |
79 | } |
80 | else |
81 | { |
82 | - stopSong(); |
83 | + player.stop(); |
84 | } |
85 | } |
86 | |
87 | - if (index < currentIndex) { |
88 | - currentIndex -= 1; |
89 | + if (index < player.currentIndex) { |
90 | + player.currentIndex -= 1; |
91 | } |
92 | |
93 | // Remove item from queue and clear caches |
94 | |
95 | === modified file 'MusicPlaylists.qml' |
96 | --- MusicPlaylists.qml 2014-01-16 19:22:52 +0000 |
97 | +++ MusicPlaylists.qml 2014-03-07 16:40:44 +0000 |
98 | @@ -42,13 +42,6 @@ |
99 | property string oldPlaylistID: "" |
100 | property string inPlaylist: "" |
101 | |
102 | - Component.onCompleted: { |
103 | - random = Settings.getSetting("shuffle") == "1" // shuffle state |
104 | - scrobble = Settings.getSetting("scrobble") == "1" // scrobble state |
105 | - lastfmusername = Settings.getSetting("lastfmusername") // lastfm username |
106 | - lastfmpassword = Settings.getSetting("lastfmpassword") // lastfm password |
107 | - } |
108 | - |
109 | onVisibleChanged: { |
110 | if (visible === true) |
111 | { |
112 | |
113 | === modified file 'MusicStart.qml' |
114 | --- MusicStart.qml 2014-02-20 01:28:22 +0000 |
115 | +++ MusicStart.qml 2014-03-07 16:40:44 +0000 |
116 | @@ -187,6 +187,7 @@ |
117 | } else { |
118 | albumTracksModel.filterAlbumTracks(title) |
119 | } |
120 | + |
121 | songsSheet.line1 = title2 |
122 | songsSheet.line2 = title |
123 | songsSheet.covers = recentItem.covers |
124 | |
125 | === modified file 'MusicToolbar.qml' |
126 | --- MusicToolbar.qml 2014-02-22 19:59:15 +0000 |
127 | +++ MusicToolbar.qml 2014-03-07 16:40:44 +0000 |
128 | @@ -262,7 +262,7 @@ |
129 | id: musicToolbarPlayerControls |
130 | anchors.fill: parent |
131 | color: styleMusic.playerControls.backgroundColor |
132 | - state: trackQueue.isEmpty === true ? "disabled" : "enabled" |
133 | + state: trackQueue.model.count === 0 ? "disabled" : "enabled" |
134 | |
135 | states: [ |
136 | State { |
137 | @@ -293,7 +293,7 @@ |
138 | id: disabledPlayerControlsGroup |
139 | anchors.fill: parent |
140 | color: "transparent" |
141 | - visible: trackQueue.isEmpty === true |
142 | + visible: trackQueue.model.count === 0 |
143 | |
144 | Label { |
145 | id: noSongsInQueueLabel |
146 | @@ -319,7 +319,7 @@ |
147 | id: enabledPlayerControlsGroup |
148 | anchors.fill: parent |
149 | color: "transparent" |
150 | - visible: trackQueue.isEmpty === false |
151 | + visible: trackQueue.model.count !== 0 |
152 | |
153 | /* Settings button */ |
154 | // TODO: Enable settings when it is practical |
155 | @@ -454,14 +454,7 @@ |
156 | |
157 | if (accepted) |
158 | { |
159 | - if (player.playbackState === MediaPlayer.PlayingState) |
160 | - { |
161 | - player.pause() |
162 | - } |
163 | - else |
164 | - { |
165 | - player.play() |
166 | - } |
167 | + player.toggle(); |
168 | } |
169 | } |
170 | } |
171 | @@ -496,7 +489,8 @@ |
172 | elide: Text.ElideRight |
173 | fontSize: "medium" |
174 | objectName: "playercontroltitle" |
175 | - text: mainView.currentTracktitle === "" ? mainView.currentFile : mainView.currentTracktitle |
176 | + text: player.currentMetaTitle === "" |
177 | + ? player.source : player.currentMetaTitle |
178 | } |
179 | |
180 | /* Artist of track */ |
181 | @@ -510,7 +504,7 @@ |
182 | color: styleMusic.playerControls.labelColor |
183 | elide: Text.ElideRight |
184 | fontSize: "small" |
185 | - text: mainView.currentArtist |
186 | + text: player.currentMetaArtist |
187 | } |
188 | |
189 | /* Album of track */ |
190 | @@ -524,7 +518,7 @@ |
191 | color: styleMusic.playerControls.labelColor |
192 | elide: Text.ElideRight |
193 | fontSize: "small" |
194 | - text: mainView.currentAlbum |
195 | + text: player.currentMetaAlbum |
196 | } |
197 | } |
198 | } |
199 | @@ -574,7 +568,7 @@ |
200 | elide: Text.ElideRight |
201 | fontSize: "medium" |
202 | objectName: "playercontroltitle" |
203 | - text: trackQueue.isEmpty ? "" : mainView.currentTracktitle === "" ? mainView.currentFile : mainView.currentTracktitle |
204 | + text: trackQueue.model.count === 0 ? "" : player.currentMetaTitle === "" ? player.currentMetaFile : player.currentMetaTitle |
205 | } |
206 | |
207 | /* Artist of track */ |
208 | @@ -589,7 +583,7 @@ |
209 | color: styleMusic.playerControls.labelColor |
210 | elide: Text.ElideRight |
211 | fontSize: "small" |
212 | - text: trackQueue.isEmpty ? "" : mainView.currentArtist |
213 | + text: trackQueue.model.count === 0 ? "" : player.currentMetaArtist |
214 | } |
215 | |
216 | /* Album of track */ |
217 | @@ -604,7 +598,7 @@ |
218 | color: styleMusic.playerControls.labelColor |
219 | elide: Text.ElideRight |
220 | fontSize: "small" |
221 | - text: trackQueue.isEmpty ? "" : mainView.currentAlbum |
222 | + text: trackQueue.model.count === 0 ? "" : player.currentMetaAlbum |
223 | } |
224 | } |
225 | /* Clicking in the area shows the queue */ |
226 | @@ -612,7 +606,7 @@ |
227 | anchors { |
228 | fill: nowPlayingWideAspectLabels |
229 | } |
230 | - enabled: !trackQueue.isEmpty |
231 | + enabled: trackQueue.model.count !== 0 |
232 | onClicked: { |
233 | nowPlaying.visible = true; |
234 | } |
235 | @@ -626,6 +620,7 @@ |
236 | anchors.rightMargin: units.gu(1) |
237 | anchors.verticalCenter: parent.verticalCenter |
238 | height: units.gu(6) |
239 | + opacity: player.repeat ? 1 : .4 |
240 | width: height |
241 | |
242 | Image { |
243 | @@ -636,7 +631,7 @@ |
244 | anchors.horizontalCenter: parent.horizontalCenter |
245 | source: Qt.resolvedUrl("images/media-playlist-repeat.svg") |
246 | verticalAlignment: Text.AlignVCenter |
247 | - opacity: Settings.getSetting("repeat") === "1" ? 1 : .4 |
248 | + opacity: player.repeat ? 1 : .4 |
249 | } |
250 | |
251 | MouseArea { |
252 | @@ -644,9 +639,7 @@ |
253 | |
254 | onClicked: { |
255 | // Invert repeat settings |
256 | - Settings.setSetting("repeat", !(Settings.getSetting("repeat") === "1")) |
257 | - console.debug("Repeat:", Settings.getSetting("repeat") === "1") |
258 | - repeatIcon.opacity = Settings.getSetting("repeat") === "1" ? 1 : .4 |
259 | + player.repeat = !player.repeat |
260 | } |
261 | } |
262 | } |
263 | @@ -659,7 +652,7 @@ |
264 | anchors.verticalCenter: parent.verticalCenter |
265 | height: units.gu(6) |
266 | objectName: "previousshape" |
267 | - opacity: trackQueue.isEmpty ? .4 : 1 |
268 | + opacity: trackQueue.model.count === 0 ? .4 : 1 |
269 | width: height |
270 | |
271 | Image { |
272 | @@ -677,7 +670,7 @@ |
273 | id: nowPlayingPreviousMouseArea |
274 | onClicked: |
275 | { |
276 | - previousSong() |
277 | + player.previousSong() |
278 | } |
279 | } |
280 | } |
281 | @@ -751,7 +744,7 @@ |
282 | width: height |
283 | anchors.horizontalCenter: parent.horizontalCenter |
284 | anchors.verticalCenter: parent.verticalCenter |
285 | - opacity: trackQueue.isEmpty ? .4 : 1 |
286 | + opacity: trackQueue.model.count === 0 ? .4 : 1 |
287 | source: player.playbackState === MediaPlayer.PlayingState ? |
288 | Qt.resolvedUrl("images/media-playback-pause.svg") : Qt.resolvedUrl("images/media-playback-start.svg") |
289 | } |
290 | @@ -779,14 +772,7 @@ |
291 | return; |
292 | } |
293 | |
294 | - if (player.playbackState === MediaPlayer.PlayingState) |
295 | - { |
296 | - player.pause() |
297 | - } |
298 | - else |
299 | - { |
300 | - player.play() |
301 | - } |
302 | + player.toggle(); |
303 | } |
304 | } |
305 | } |
306 | @@ -804,7 +790,7 @@ |
307 | anchors.verticalCenter: parent.verticalCenter |
308 | height: units.gu(6) |
309 | objectName: "forwardshape" |
310 | - opacity: trackQueue.isEmpty ? .4 : 1 |
311 | + opacity: trackQueue.model.count === 0 ? .4 : 1 |
312 | width: height |
313 | |
314 | Image { |
315 | @@ -822,7 +808,7 @@ |
316 | id: nowPlayingNextMouseArea |
317 | onClicked: |
318 | { |
319 | - nextSong() |
320 | + player.nextSong() |
321 | } |
322 | } |
323 | } |
324 | @@ -835,6 +821,7 @@ |
325 | anchors.leftMargin: units.gu(1) |
326 | anchors.verticalCenter: parent.verticalCenter |
327 | height: units.gu(6) |
328 | + opacity: player.shuffle ? 1 : .4 |
329 | width: height |
330 | |
331 | Image { |
332 | @@ -844,7 +831,7 @@ |
333 | anchors.verticalCenter: parent.verticalCenter |
334 | anchors.horizontalCenter: parent.horizontalCenter |
335 | source: Qt.resolvedUrl("images/media-playlist-shuffle.svg") |
336 | - opacity: Settings.getSetting("shuffle") === "1" ? 1 : .4 |
337 | + opacity: player.shuffle ? 1 : .4 |
338 | } |
339 | |
340 | MouseArea { |
341 | @@ -852,11 +839,7 @@ |
342 | |
343 | onClicked: { |
344 | // Invert shuffle settings |
345 | - mainView.random = !mainView.random |
346 | - shuffleIcon.opacity = mainView.random ? 1 : .4 |
347 | - Settings.setSetting("shuffle", mainView.random) |
348 | - console.debug("Shuffle:", Settings.getSetting("shuffle") === "1") |
349 | - |
350 | + player.shuffle = !player.shuffle |
351 | } |
352 | } |
353 | } |
354 | @@ -917,7 +900,7 @@ |
355 | fontSize: "x-small" |
356 | height: parent.height |
357 | horizontalAlignment: Text.AlignHCenter |
358 | - text: player.positionStr |
359 | + text: durationToString(player.position) |
360 | verticalAlignment: Text.AlignVCenter |
361 | width: units.gu(3) |
362 | } |
363 | @@ -932,7 +915,7 @@ |
364 | anchors.verticalCenter: parent.verticalCenter |
365 | color: "transparent" |
366 | height: units.gu(1); |
367 | - state: trackQueue.isEmpty === true ? "disabled" : "enabled" |
368 | + state: trackQueue.model.count === 0 ? "disabled" : "enabled" |
369 | |
370 | states: [ |
371 | State { |
372 | @@ -967,19 +950,23 @@ |
373 | } |
374 | ] |
375 | |
376 | - // Connection from positionChanged signal |
377 | - function updatePosition(position, duration) |
378 | - { |
379 | - if (player.seeking == false) |
380 | - { |
381 | - musicToolbarFullProgressHandle.x = ((position / duration) * musicToolbarFullProgressBarContainer.width) |
382 | - - musicToolbarFullProgressHandle.width / 2; |
383 | + property bool seeking: false |
384 | + |
385 | + onSeekingChanged: { |
386 | + if (seeking === false) { |
387 | + musicToolbarFullPositionLabel.text = durationToString(player.position) |
388 | } |
389 | } |
390 | |
391 | - Component.onCompleted: { |
392 | - // Connect to signal from MediaPlayer |
393 | - player.positionChange.connect(updatePosition) |
394 | + Connections { |
395 | + target: player |
396 | + onPositionChanged: { |
397 | + if (musicToolbarFullProgressBarContainer.seeking === false) |
398 | + { |
399 | + musicToolbarFullProgressHandle.x = (player.position / player.duration) * musicToolbarFullProgressBarContainer.width |
400 | + - musicToolbarFullProgressHandle.width / 2; |
401 | + } |
402 | + } |
403 | } |
404 | |
405 | // Black background behind the progress bar |
406 | @@ -1016,14 +1003,7 @@ |
407 | // On X change update the position string |
408 | onXChanged: { |
409 | var fraction = (x + (width / 2)) / parent.width; |
410 | - player.positionStr = __durationToString(fraction * player.duration); |
411 | - } |
412 | - |
413 | - transitions: Transition { |
414 | - NumberAnimation { |
415 | - properties: "x" |
416 | - duration: 1000 |
417 | - } |
418 | + musicToolbarFullPositionLabel.text = durationToString(fraction * player.duration) |
419 | } |
420 | } |
421 | } |
422 | @@ -1038,7 +1018,7 @@ |
423 | fontSize: "x-small" |
424 | height: parent.height |
425 | horizontalAlignment: Text.AlignHCenter |
426 | - text: player.durationStr |
427 | + text: durationToString(player.duration) |
428 | verticalAlignment: Text.AlignVCenter |
429 | width: units.gu(3) |
430 | } |
431 | @@ -1072,13 +1052,11 @@ |
432 | height: parent.height |
433 | width: 0 |
434 | |
435 | - function updatePosition(position, duration) |
436 | - { |
437 | - musicToolbarSmallProgressHint.width = (position / duration) * musicToolbarSmallProgressBackground.width |
438 | - } |
439 | - |
440 | - Component.onCompleted: { |
441 | - player.positionChange.connect(updatePosition) |
442 | + Connections { |
443 | + target: player |
444 | + onPositionChanged: { |
445 | + musicToolbarSmallProgressHint.width = (player.position / player.duration) * musicToolbarSmallProgressBackground.width |
446 | + } |
447 | } |
448 | } |
449 | } |
450 | @@ -1191,7 +1169,8 @@ |
451 | drag.target: musicToolbarFullProgressHandle |
452 | |
453 | onPressed: { |
454 | - player.seeking = true; |
455 | + musicToolbarFullProgressBarContainer.seeking = true; |
456 | + |
457 | // Jump the handle to the current mouse position |
458 | musicToolbarFullProgressHandle.x = mouse.x - (musicToolbarFullProgressHandle.width / 2); |
459 | } |
460 | @@ -1204,7 +1183,7 @@ |
461 | fraction = fraction > 1 ? 1 : fraction |
462 | |
463 | player.seek((fraction) * player.duration); |
464 | - player.seeking = false; |
465 | + musicToolbarFullProgressBarContainer.seeking = false; |
466 | } |
467 | } |
468 | |
469 | |
470 | === modified file 'MusicTracks.qml' |
471 | --- MusicTracks.qml 2014-02-24 00:38:11 +0000 |
472 | +++ MusicTracks.qml 2014-03-07 16:40:44 +0000 |
473 | @@ -49,11 +49,6 @@ |
474 | highlightFollowsCurrentItem: false |
475 | model: libraryModel.model |
476 | delegate: trackDelegate |
477 | - onCountChanged: { |
478 | - //customdebug("onCountChanged: " + tracklist.count) // activate later |
479 | - tracklist.currentIndex = libraryModel.indexOf(currentFile) |
480 | - } |
481 | - |
482 | Component { |
483 | id: trackDelegate |
484 | ListItem.Standard { |
485 | |
486 | === added file 'Player.qml' |
487 | --- Player.qml 1970-01-01 00:00:00 +0000 |
488 | +++ Player.qml 2014-03-07 16:40:44 +0000 |
489 | @@ -0,0 +1,196 @@ |
490 | +/* |
491 | + * Copyright (C) 2013 Andrew Hayzen <ahayzen@gmail.com> |
492 | + * Daniel Holm <d.holmen@gmail.com> |
493 | + * Victor Thompson <victor.thompson@gmail.com> |
494 | + * |
495 | + * This program is free software; you can redistribute it and/or modify |
496 | + * it under the terms of the GNU General Public License as published by |
497 | + * the Free Software Foundation; version 3. |
498 | + * |
499 | + * This program is distributed in the hope that it will be useful, |
500 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
501 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
502 | + * GNU General Public License for more details. |
503 | + * |
504 | + * You should have received a copy of the GNU General Public License |
505 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
506 | + */ |
507 | + |
508 | +import QtQuick 2.0 |
509 | +import QtMultimedia 5.0 |
510 | +import QtQuick.LocalStorage 2.0 |
511 | +import "settings.js" as Settings |
512 | + |
513 | +/* |
514 | + * This file should *only* manage the media playing and the relevant settings |
515 | + * It should therefore only access MediaPlayer, trackQueue and Settings |
516 | + * Anything else within the app should use Connections to listen for changes |
517 | + */ |
518 | + |
519 | + |
520 | +Item { |
521 | + objectName: "player" |
522 | + |
523 | + property string currentMetaAlbum: "" |
524 | + property string currentMetaArtist: "" |
525 | + property string currentMetaCover: "" |
526 | + property string currentMetaFile: "" |
527 | + property string currentMetaGenre: "" |
528 | + property string currentMetaLength: "" |
529 | + property string currentMetaTitle: "" |
530 | + property string currentMetaYear: "" |
531 | + property int currentIndex: -1 |
532 | + property alias duration: mediaPlayer.duration |
533 | + property bool isPlaying: player.playbackState === MediaPlayer.PlayingState |
534 | + property alias playbackState: mediaPlayer.playbackState |
535 | + property alias position: mediaPlayer.position |
536 | + property bool repeat: Settings.getSetting("repeat") === "1" |
537 | + property bool shuffle: Settings.getSetting("shuffle") === "1" |
538 | + property alias source: mediaPlayer.source |
539 | + |
540 | + onRepeatChanged: { |
541 | + Settings.setSetting("repeat", repeat ? "1" : "0") |
542 | + console.debug("Repeat:", Settings.getSetting("repeat") === "1") |
543 | + } |
544 | + |
545 | + onShuffleChanged: { |
546 | + Settings.setSetting("shuffle", shuffle ? "1" : "0") |
547 | + console.debug("Shuffle:", Settings.getSetting("shuffle") === "1") |
548 | + } |
549 | + |
550 | + function getSong(direction, startPlaying, fromControls) { |
551 | + // Seek to start if threshold reached when selecting previous |
552 | + if (direction === -1 && (player.position / 1000) > 5) |
553 | + { |
554 | + player.seek(0); // seek to start |
555 | + return; |
556 | + } |
557 | + |
558 | + if (trackQueue.model.count == 0) |
559 | + { |
560 | + customdebug("No tracks in queue."); |
561 | + return; |
562 | + } |
563 | + |
564 | + // default fromControls and startPlaying to true |
565 | + fromControls = fromControls === undefined ? true : fromControls; |
566 | + startPlaying = startPlaying === undefined ? true : startPlaying; |
567 | + var newIndex; |
568 | + |
569 | + console.log("currentIndex: " + currentIndex) |
570 | + console.log("trackQueue.count: " + trackQueue.model.count) |
571 | + |
572 | + if (shuffle) { |
573 | + var now = new Date(); |
574 | + var seed = now.getSeconds(); |
575 | + |
576 | + // trackQueue must be above 1 otherwise an infinite loop will occur |
577 | + do { |
578 | + newIndex = (Math.floor((trackQueue.model.count) |
579 | + * Math.random(seed))); |
580 | + } while (newIndex === currentIndex && trackQueue.model.count > 1) |
581 | + } else { |
582 | + if ((currentIndex < trackQueue.model.count - 1 && direction === 1 ) |
583 | + || (currentIndex > 0 && direction === -1)) { |
584 | + newIndex = currentIndex + direction |
585 | + } else if(direction === 1 && (Settings.getSetting("repeat") === "1" |
586 | + || fromControls)) { |
587 | + newIndex = 0 |
588 | + } else if(direction === -1 && (Settings.getSetting("repeat") === "1" || fromControls)) { |
589 | + newIndex = trackQueue.model.count - 1 |
590 | + } |
591 | + else |
592 | + { |
593 | + player.stop() |
594 | + return; |
595 | + } |
596 | + } |
597 | + |
598 | + if (startPlaying) { // only start the track if told |
599 | + playSong(trackQueue.model.get(newIndex).file, newIndex) |
600 | + } |
601 | + else { |
602 | + currentIndex = newIndex |
603 | + source = Qt.resolvedUrl(trackQueue.model.get(newIndex).file) |
604 | + } |
605 | + } |
606 | + |
607 | + function nextSong(startPlaying, fromControls) { |
608 | + getSong(1, startPlaying, fromControls) |
609 | + } |
610 | + |
611 | + function pause() { |
612 | + mediaPlayer.pause(); |
613 | + } |
614 | + |
615 | + function play() { |
616 | + mediaPlayer.play(); |
617 | + } |
618 | + |
619 | + function playSong(filepath, index) { |
620 | + player.stop(); |
621 | + currentIndex = index; |
622 | + player.source = Qt.resolvedUrl(filepath); |
623 | + player.play(); |
624 | + } |
625 | + |
626 | + function previousSong(startPlaying) { |
627 | + getSong(-1, startPlaying) |
628 | + } |
629 | + |
630 | + function seek(position) { |
631 | + mediaPlayer.seek(position); |
632 | + } |
633 | + |
634 | + function stop() { |
635 | + mediaPlayer.stop(); |
636 | + } |
637 | + |
638 | + function toggle() { |
639 | + if (player.playbackState == MediaPlayer.PlayingState) { |
640 | + player.pause() |
641 | + } |
642 | + else { |
643 | + player.play() |
644 | + } |
645 | + } |
646 | + |
647 | + MediaPlayer { |
648 | + id: mediaPlayer |
649 | + muted: false |
650 | + |
651 | + onSourceChanged: { |
652 | + // Force invalid source to "" |
653 | + if (source === undefined || source === false) { |
654 | + source = "" |
655 | + return |
656 | + } |
657 | + |
658 | + if (source === "") { |
659 | + currentIndex = -1 |
660 | + player.stop() |
661 | + } |
662 | + else { |
663 | + var obj = trackQueue.model.get(player.currentIndex); |
664 | + currentMetaAlbum = obj.album; |
665 | + currentMetaArtist = obj.artist; |
666 | + currentMetaCover = obj.cover; |
667 | + currentMetaFile = obj.file; |
668 | + currentMetaGenre = obj.genre; |
669 | + currentMetaLength = obj.length; |
670 | + currentMetaTitle = obj.title; |
671 | + currentMetaYear = obj.year; |
672 | + } |
673 | + |
674 | + console.log("Source: " + source.toString()) |
675 | + console.log("Index: " + currentIndex) |
676 | + } |
677 | + |
678 | + onStatusChanged: { |
679 | + if (status == MediaPlayer.EndOfMedia) { |
680 | + nextSong(true, false) // next track |
681 | + } |
682 | + } |
683 | + } |
684 | +} |
685 | + |
686 | |
687 | === modified file 'common/AlbumsSheet.qml' |
688 | --- common/AlbumsSheet.qml 2014-03-06 17:23:56 +0000 |
689 | +++ common/AlbumsSheet.qml 2014-03-07 16:40:44 +0000 |
690 | @@ -51,10 +51,6 @@ |
691 | model: artistAlbumsModel.model |
692 | delegate: albumTracksDelegate |
693 | |
694 | - onCountChanged: { |
695 | - albumtrackslist.currentIndex = albumTracksModel.indexOf(currentFile) |
696 | - } |
697 | - |
698 | Component { |
699 | id: albumTracksDelegate |
700 | |
701 | |
702 | === modified file 'common/BlurredBackground.qml' |
703 | --- common/BlurredBackground.qml 2013-12-15 05:28:37 +0000 |
704 | +++ common/BlurredBackground.qml 2014-03-07 16:40:44 +0000 |
705 | @@ -23,7 +23,9 @@ |
706 | // Blurred background |
707 | Rectangle { |
708 | anchors.fill: parent |
709 | - property string cover: mainView.currentCoverFull |
710 | + property string cover: player.currentMetaCover !== "" ? |
711 | + player.currentMetaCover : |
712 | + "images/cover_default.png" |
713 | // the album art |
714 | Image { |
715 | id: backgroundImage |
716 | |
717 | === modified file 'music-app.qml' |
718 | --- music-app.qml 2014-03-06 21:13:48 +0000 |
719 | +++ music-app.qml 2014-03-07 16:40:44 +0000 |
720 | @@ -83,7 +83,7 @@ |
721 | id: nextAction |
722 | text: i18n.tr("Next") |
723 | keywords: i18n.tr("Next Track") |
724 | - onTriggered: nextSong() |
725 | + onTriggered: player.nextSong() |
726 | } |
727 | Action { |
728 | id: playsAction |
729 | @@ -91,13 +91,7 @@ |
730 | i18n.tr("Pause") : i18n.tr("Play") |
731 | keywords: player.playbackState === MediaPlayer.PlayingState ? |
732 | i18n.tr("Pause Playback") : i18n.tr("Continue or start playback") |
733 | - onTriggered: { |
734 | - if (player.playbackState === MediaPlayer.PlayingState) { |
735 | - player.pause() |
736 | - } else { |
737 | - player.play() |
738 | - } |
739 | - } |
740 | + onTriggered: player.toggle() |
741 | } |
742 | Action { |
743 | id: backAction |
744 | @@ -112,7 +106,7 @@ |
745 | id: prevAction |
746 | text: i18n.tr("Previous") |
747 | keywords: i18n.tr("Previous Track") |
748 | - onTriggered: previousSong() |
749 | + onTriggered: player.previousSong() |
750 | } |
751 | Action { |
752 | id: stopAction |
753 | @@ -190,6 +184,36 @@ |
754 | domain: "com.ubuntu.music" |
755 | } |
756 | |
757 | + // Connections for usermetrics |
758 | + Connections { |
759 | + id: userMetricPlayerConnection |
760 | + target: player |
761 | + property bool songCounted: false |
762 | + |
763 | + onSourceChanged: { |
764 | + songCounted = false |
765 | + } |
766 | + |
767 | + onPositionChanged: { |
768 | + // Increment song count on Welcome screen if song has been |
769 | + // playing for over 10 seconds. |
770 | + if (player.position > 10000 && !songCounted) { |
771 | + songCounted = true |
772 | + songsMetric.increment() |
773 | + console.debug("Increment UserMetrics") |
774 | + } |
775 | + } |
776 | + } |
777 | + |
778 | + // Connections for powerd |
779 | + Connections { |
780 | + target: player |
781 | + onPlaybackStateChanged: { |
782 | + QtPowerd.keepAlive = player.playbackState === MediaPlayer.PlayingState |
783 | + console.log("QtPowerd.keepAlive=" + QtPowerd.keepAlive) |
784 | + } |
785 | + } |
786 | + |
787 | // Design stuff |
788 | Style { id: styleMusic } |
789 | width: units.gu(100) |
790 | @@ -234,7 +258,6 @@ |
791 | Playlists.initializePlaylist() |
792 | // everything else |
793 | loading.visible = true |
794 | - random = Settings.getSetting("shuffle") == "1" // shuffle state |
795 | scrobble = Settings.getSetting("scrobble") == "1" // scrobble state |
796 | lastfmusername = Settings.getSetting("lastfmusername") // lastfm username |
797 | lastfmpassword = Settings.getSetting("lastfmpassword") // lastfm password |
798 | @@ -250,10 +273,7 @@ |
799 | // VARIABLES |
800 | property string musicName: i18n.tr("Music") |
801 | property string appVersion: '1.2' |
802 | - property bool isPlaying: false |
803 | - property bool songCounted: false |
804 | property bool hasRecent: !Library.isRecentEmpty() |
805 | - property bool random: false |
806 | property bool scrobble: false |
807 | property string lastfmusername |
808 | property string lastfmpassword |
809 | @@ -266,26 +286,13 @@ |
810 | property string chosenCover: "" |
811 | property string chosenGenre: "" |
812 | property int chosenIndex: 0 |
813 | - property string currentArtist: "" |
814 | - property string currentAlbum: "" |
815 | - property string currentTracktitle: "" |
816 | - property string currentFile: "" |
817 | - property int currentIndex: -1 |
818 | property LibraryListModel currentModel: null // Current model being used |
819 | property var currentQuery: null |
820 | property var currentParam: null |
821 | - property string currentCover: "" |
822 | - property string currentCoverSmall: currentCover === "" ? |
823 | - "images/cover_default_icon.png" : |
824 | - currentCover |
825 | - property string currentCoverFull: currentCover !== "" ? |
826 | - currentCover : |
827 | - "images/cover_default.png" |
828 | property bool queueChanged: false |
829 | property bool toolbarShown: musicToolbar.shown |
830 | signal collapseExpand(int index); |
831 | signal collapseSwipeDelete(int index); |
832 | - signal onPlayingTrackChange(string source) |
833 | signal onToolbarShownChanged(bool shown, var currentPage, var currentTab) |
834 | |
835 | property bool wideAspect: width >= units.gu(70) |
836 | @@ -301,105 +308,6 @@ |
837 | } |
838 | } |
839 | |
840 | - function previousSong(startPlaying) { |
841 | - getSong(-1, startPlaying) |
842 | - } |
843 | - |
844 | - |
845 | - function nextSong(startPlaying, fromControls) { |
846 | - getSong(1, startPlaying, fromControls) |
847 | - } |
848 | - |
849 | - function stopSong() { |
850 | - currentIndex = -1; |
851 | - player.source = ""; // changing to "" triggers the player to stop and removes the highlight |
852 | - } |
853 | - |
854 | - function getSong(direction, startPlaying, fromControls) { |
855 | - |
856 | - // Reset the songCounted property to false since this is a new track |
857 | - songCounted = false |
858 | - |
859 | - // Seek to start if threshold reached when selecting previous |
860 | - if (direction === -1 && (player.position / 1000) > 5) |
861 | - { |
862 | - player.seek(0); // seek to start |
863 | - return; |
864 | - } |
865 | - |
866 | - if (trackQueue.model.count == 0) |
867 | - { |
868 | - customdebug("No tracks in queue."); |
869 | - return; |
870 | - } |
871 | - |
872 | - if (startPlaying === undefined) // default startPlaying to true |
873 | - { |
874 | - startPlaying = true; |
875 | - } |
876 | - |
877 | - if (fromControls === undefined) // default fromControls to true |
878 | - { |
879 | - fromControls = true; |
880 | - } |
881 | - |
882 | - if (random) { |
883 | - var now = new Date(); |
884 | - var seed = now.getSeconds(); |
885 | - |
886 | - // trackQueue must be above 1 otherwise an infinite loop will occur |
887 | - do { |
888 | - var num = (Math.floor((trackQueue.model.count) * Math.random(seed))); |
889 | - console.log(num) |
890 | - } while (num == currentIndex && trackQueue.model.count > 1) |
891 | - currentIndex = num |
892 | - player.source = Qt.resolvedUrl(trackQueue.model.get(num).file) |
893 | - console.log("MediaPlayer statusChanged, currentIndex: " + currentIndex) |
894 | - } else { |
895 | - if ((currentIndex < trackQueue.model.count - 1 && direction === 1 ) |
896 | - || (currentIndex > 0 && direction === -1)) { |
897 | - console.log("currentIndex: " + currentIndex) |
898 | - console.log("trackQueue.count: " + trackQueue.model.count) |
899 | - |
900 | - currentIndex += direction |
901 | - player.source = Qt.resolvedUrl(trackQueue.model.get(currentIndex).file) |
902 | - } else if(direction === 1 && (Settings.getSetting("repeat") === "1" || fromControls)) { |
903 | - console.log("currentIndex: " + currentIndex) |
904 | - console.log("trackQueue.count: " + trackQueue.model.count) |
905 | - currentIndex = 0 |
906 | - player.source = Qt.resolvedUrl(trackQueue.model.get(currentIndex).file) |
907 | - } else if(direction === -1 && (Settings.getSetting("repeat") === "1" || fromControls)) { |
908 | - console.log("currentIndex: " + currentIndex) |
909 | - console.log("trackQueue.count: " + trackQueue.model.count) |
910 | - currentIndex = trackQueue.model.count - 1 |
911 | - player.source = Qt.resolvedUrl(trackQueue.model.get(currentIndex).file) |
912 | - } |
913 | - else |
914 | - { |
915 | - player.stop() |
916 | - return; |
917 | - } |
918 | - |
919 | - console.log("MediaPlayer statusChanged, currentIndex: " + currentIndex) |
920 | - } |
921 | - player.stop() // Add stop so that if same song is selected it restarts |
922 | - console.log("Playing: "+player.source) |
923 | - |
924 | - if (startPlaying === true) // only start the track if told |
925 | - { |
926 | - player.play() |
927 | - } |
928 | - |
929 | - timestamp = new Date().getTime(); // contains current date and time in Unix time, used to scrobble |
930 | - // scrobble it |
931 | - if (Settings.getSetting("scrobble") === "1") { |
932 | - Scrobble.now_playing(player.source,timestamp) // send "now playing" to last.fm |
933 | - } |
934 | - else { |
935 | - console.debug("Debug: no scrobbling") |
936 | - } |
937 | - } |
938 | - |
939 | // Add items from a stored query in libraryModel into the queue |
940 | function addQueueFromModel(libraryModel) |
941 | { |
942 | @@ -425,22 +333,23 @@ |
943 | } |
944 | } |
945 | |
946 | + // Converts an duration in ms to a formated string ("minutes:seconds") |
947 | + function durationToString(duration) { |
948 | + var minutes = Math.floor((duration/1000) / 60); |
949 | + var seconds = Math.floor((duration/1000)) % 60; |
950 | + return minutes + ":" + (seconds<10 ? "0"+seconds : seconds); |
951 | + } |
952 | + |
953 | function trackClicked(libraryModel, index, play) |
954 | { |
955 | - if (play === undefined) |
956 | - { |
957 | - play = true |
958 | - } |
959 | + play = play === undefined ? true : play // default play to true |
960 | |
961 | - if (index > libraryModel.model.count - 1 || index < 0) |
962 | - { |
963 | + if (index > libraryModel.model.count - 1 || index < 0) { |
964 | customdebug("Incorrect index given to trackClicked.") |
965 | return; |
966 | } |
967 | |
968 | - var file = libraryModel.model.get(index).file |
969 | - |
970 | - console.debug(player.source, Qt.resolvedUrl(file)) |
971 | + var file = Qt.resolvedUrl(libraryModel.model.get(index).file) |
972 | |
973 | // Clear the play queue and load the new tracks - if not trackQueue |
974 | // Don't reload queue if model, query and parameters are the same |
975 | @@ -454,31 +363,16 @@ |
976 | trackQueue.model.clear() |
977 | addQueueFromModel(libraryModel) |
978 | } |
979 | - else if (player.source == Qt.resolvedUrl(file) && |
980 | - currentIndex === index) |
981 | + else if (player.source == file && |
982 | + player.currentIndex === index) |
983 | { |
984 | - if (play === false) |
985 | - { |
986 | - return |
987 | - } |
988 | - |
989 | - console.log("Is current track: "+player.playbackState) |
990 | - |
991 | - if (player.playbackState == MediaPlayer.PlayingState) |
992 | - { |
993 | + // Same track so just toggle playing state |
994 | + if (play === true) { |
995 | + console.log("Is current track: "+player.playbackState) |
996 | + |
997 | if (musicToolbar.currentPage == nowPlaying) { |
998 | - player.pause() |
999 | - } else { // We are not on the now playing page |
1000 | - // Show the Now Playing page and make sure the track is visible |
1001 | - nowPlaying.visible = true; |
1002 | - nowPlaying.ensureVisibleIndex = index; |
1003 | - |
1004 | - musicToolbar.showToolbar(); |
1005 | + player.toggle() |
1006 | } |
1007 | - } |
1008 | - else |
1009 | - { |
1010 | - player.play() |
1011 | |
1012 | // Show the Now Playing page and make sure the track is visible |
1013 | nowPlaying.visible = true; |
1014 | @@ -490,142 +384,37 @@ |
1015 | return |
1016 | } |
1017 | |
1018 | - // Reset the songCounted property to false since this is a new track |
1019 | - songCounted = false |
1020 | - |
1021 | // Current index must be updated before player.source |
1022 | currentModel = libraryModel |
1023 | currentQuery = libraryModel.query |
1024 | currentParam = libraryModel.param |
1025 | - currentIndex = trackQueue.model.get(index).file === file ? |
1026 | - index : trackQueue.indexOf(file) // pick given index first |
1027 | + |
1028 | + if (Qt.resolvedUrl(trackQueue.model.get(index).file) != file) { |
1029 | + index = trackQueue.indexOf(file) // pick given index first |
1030 | + } |
1031 | queueChanged = false |
1032 | |
1033 | console.log("Click of fileName: " + file) |
1034 | |
1035 | - if (play === true) |
1036 | - { |
1037 | - player.stop() |
1038 | - } |
1039 | - |
1040 | - if (player.source == Qt.resolvedUrl(file)) { |
1041 | - onPlayingTrackChange(player.source) |
1042 | - } |
1043 | - |
1044 | - player.source = Qt.resolvedUrl(file) |
1045 | - |
1046 | - if (play === true) |
1047 | - { |
1048 | - player.play() |
1049 | - } |
1050 | - |
1051 | - console.log("Source: " + player.source.toString()) |
1052 | - console.log("Index: " + currentIndex) |
1053 | - |
1054 | - if (play === true) |
1055 | - { |
1056 | + if (play === true) { |
1057 | + player.playSong(file, index) |
1058 | + |
1059 | // Show the Now Playing page and make sure the track is visible |
1060 | nowPlaying.visible = true; |
1061 | nowPlaying.ensureVisibleIndex = index; |
1062 | |
1063 | musicToolbar.showToolbar(); |
1064 | } |
1065 | + else { |
1066 | + player.source = file |
1067 | + } |
1068 | |
1069 | return file |
1070 | } |
1071 | |
1072 | - function updateMeta() |
1073 | - { |
1074 | - // Load metadata for the track |
1075 | - currentArtist = trackQueue.model.get(currentIndex).artist |
1076 | - currentAlbum = trackQueue.model.get(currentIndex).album |
1077 | - currentTracktitle = trackQueue.model.get(currentIndex).title |
1078 | - |
1079 | - // hasCover and currentCover require no file:// |
1080 | - var file = currentFile |
1081 | - |
1082 | - if (file.indexOf("file://") == 0) |
1083 | - { |
1084 | - file = file.slice(7, file.length) |
1085 | - } |
1086 | - |
1087 | - currentCover = trackQueue.model.get(currentIndex).cover !== "" ? trackQueue.model.get(currentIndex).cover : "images/cover_default_icon.png" |
1088 | - } |
1089 | - |
1090 | // WHERE THE MAGIC HAPPENS |
1091 | - MediaPlayer { |
1092 | + Player { |
1093 | id: player |
1094 | - objectName: "player" |
1095 | - muted: false |
1096 | - |
1097 | - signal positionChange(int position, int duration) |
1098 | - |
1099 | - property bool seeking: false; // Is the user seeking? |
1100 | - |
1101 | - // String versions of pos/dur that labels listen to |
1102 | - property string durationStr: "00:00" |
1103 | - property string positionStr: "00:00" |
1104 | - |
1105 | - onSourceChanged: { |
1106 | - currentFile = source |
1107 | - |
1108 | - if (source != "" && source != undefined && source !== false) |
1109 | - { |
1110 | - onPlayingTrackChange(source) |
1111 | - updateMeta() |
1112 | - } |
1113 | - else |
1114 | - { |
1115 | - onPlayingTrackChange(source) // removes highlight as will get -1 index |
1116 | - player.stop() |
1117 | - } |
1118 | - } |
1119 | - |
1120 | - onStatusChanged: { |
1121 | - if (status == MediaPlayer.EndOfMedia) { |
1122 | - // scrobble it |
1123 | - if (Settings.getSetting("scrobble") === "1") { |
1124 | - Scrobble.scrobble(player.source,currentArtist,timestamp) |
1125 | - } |
1126 | - else { |
1127 | - console.debug("Debug: no scrobbling") |
1128 | - } |
1129 | - |
1130 | - nextSong (true, false) // next track |
1131 | - } |
1132 | - } |
1133 | - |
1134 | - // Update the duration text unless seeking (seeking overrides the text) |
1135 | - onDurationChanged: { |
1136 | - if (seeking == false) |
1137 | - { |
1138 | - durationStr = __durationToString(player.duration) |
1139 | - } |
1140 | - |
1141 | - positionChange(position, duration) |
1142 | - } |
1143 | - |
1144 | - // Update the position text unless seeking (seeking overrides the text) |
1145 | - onPositionChanged: { |
1146 | - if (seeking == false) |
1147 | - { |
1148 | - positionStr = __durationToString(player.position) |
1149 | - } |
1150 | - |
1151 | - // Increment song count on Welcome screen if song has been playing for over 10 seconds. |
1152 | - if (player.position > 10000 && !songCounted) { |
1153 | - songCounted = true |
1154 | - songsMetric.increment() |
1155 | - } |
1156 | - |
1157 | - positionChange(position, duration) |
1158 | - } |
1159 | - |
1160 | - onPlaybackStateChanged: { |
1161 | - mainView.isPlaying = player.playbackState === MediaPlayer.PlayingState |
1162 | - QtPowerd.keepAlive = mainView.isPlaying |
1163 | - console.log("mainView.isPlaying=" + mainView.isPlaying + ", QtPowerd.keepAlive=" + QtPowerd.keepAlive) |
1164 | - } |
1165 | } |
1166 | |
1167 | SongsSheet { |
1168 | @@ -933,21 +722,6 @@ |
1169 | // list of tracks on startup. This is just during development |
1170 | LibraryListModel { |
1171 | id: trackQueue |
1172 | - property bool isEmpty: count == 0 |
1173 | - |
1174 | - onIsEmptyChanged: { |
1175 | - /* |
1176 | - * If changed to false then must have been empty before |
1177 | - * Therefore set the first song as the current item |
1178 | - * and update any metadata |
1179 | - */ |
1180 | - if (isEmpty === false && currentIndex == -1 && player.source == "") |
1181 | - { |
1182 | - currentIndex = 0; |
1183 | - player.source = trackQueue.model.get(currentIndex).file; |
1184 | - updateMeta(); |
1185 | - } |
1186 | - } |
1187 | } |
1188 | |
1189 | // list of songs, which has been removed. |
1190 | @@ -1294,11 +1068,4 @@ |
1191 | id: addtoPlaylist |
1192 | } |
1193 | |
1194 | - // Converts an duration in ms to a formated string ("minutes:seconds") |
1195 | - function __durationToString(duration) { |
1196 | - var minutes = Math.floor((duration/1000) / 60); |
1197 | - var seconds = Math.floor((duration/1000)) % 60; |
1198 | - return minutes + ":" + (seconds<10 ? "0"+seconds : seconds); |
1199 | - } |
1200 | - |
1201 | } // end of main view |
1202 | |
1203 | === modified file 'tests/autopilot/music_app/emulators.py' |
1204 | --- tests/autopilot/music_app/emulators.py 2014-01-17 22:24:22 +0000 |
1205 | +++ tests/autopilot/music_app/emulators.py 2014-03-07 16:40:44 +0000 |
1206 | @@ -51,6 +51,9 @@ |
1207 | |
1208 | self.pointing_device.drag(x1, y1, x1, y1 - toolbar.height) |
1209 | |
1210 | + def get_player(self): |
1211 | + return self.select_single("*", objectName="player") |
1212 | + |
1213 | def get_play_button(self): |
1214 | return self.wait_select_single("*", objectName="playshape") |
1215 | |
1216 | |
1217 | === modified file 'tests/autopilot/music_app/tests/__init__.py' |
1218 | --- tests/autopilot/music_app/tests/__init__.py 2014-01-31 20:43:59 +0000 |
1219 | +++ tests/autopilot/music_app/tests/__init__.py 2014-03-07 16:40:44 +0000 |
1220 | @@ -242,5 +242,9 @@ |
1221 | logger.error("Failed to restore database") |
1222 | |
1223 | @property |
1224 | + def player(self): |
1225 | + return self.main_view.get_player() |
1226 | + |
1227 | + @property |
1228 | def main_view(self): |
1229 | return self.app.select_single(emulators.MainView) |
1230 | |
1231 | === modified file 'tests/autopilot/music_app/tests/test_music.py' |
1232 | --- tests/autopilot/music_app/tests/test_music.py 2014-03-06 17:23:56 +0000 |
1233 | +++ tests/autopilot/music_app/tests/test_music.py 2014-03-07 16:40:44 +0000 |
1234 | @@ -41,8 +41,8 @@ |
1235 | song = self.main_view.get_album_sheet_listview_tracktitle(trackTitle) |
1236 | self.pointing_device.click_object(song) |
1237 | |
1238 | - title = lambda: self.main_view.currentTracktitle |
1239 | - artist = lambda: self.main_view.currentArtist |
1240 | + title = lambda: self.player.currentMetaTitle |
1241 | + artist = lambda: self.player.currentMetaArtist |
1242 | self.assertThat(title, |
1243 | Eventually(Equals("Foss Yeaaaah! (Radio Edit)"))) |
1244 | self.assertThat(artist, Eventually(Equals("Benjamin Kerensa"))) |
1245 | @@ -69,15 +69,15 @@ |
1246 | playbutton = self.main_view.get_play_button() |
1247 | |
1248 | """ Track is playing""" |
1249 | - self.assertThat(self.main_view.isPlaying, Eventually(Equals(True))) |
1250 | + self.assertThat(self.player.isPlaying, Eventually(Equals(True))) |
1251 | self.pointing_device.click_object(playbutton) |
1252 | |
1253 | """ Track is not playing""" |
1254 | - self.assertThat(self.main_view.isPlaying, Eventually(Equals(False))) |
1255 | + self.assertThat(self.player.isPlaying, Eventually(Equals(False))) |
1256 | |
1257 | """ Track is playing""" |
1258 | self.pointing_device.click_object(playbutton) |
1259 | - self.assertThat(self.main_view.isPlaying, Eventually(Equals(True))) |
1260 | + self.assertThat(self.player.isPlaying, Eventually(Equals(True))) |
1261 | |
1262 | def test_play_pause_now_playing(self): |
1263 | """ Test playing and pausing a track (Music Library must exist) """ |
1264 | @@ -92,15 +92,15 @@ |
1265 | playbutton = self.main_view.get_now_playing_play_button() |
1266 | |
1267 | """ Track is playing""" |
1268 | - self.assertThat(self.main_view.isPlaying, Eventually(Equals(True))) |
1269 | + self.assertThat(self.player.isPlaying, Eventually(Equals(True))) |
1270 | self.pointing_device.click_object(playbutton) |
1271 | |
1272 | """ Track is not playing""" |
1273 | - self.assertThat(self.main_view.isPlaying, Eventually(Equals(False))) |
1274 | + self.assertThat(self.player.isPlaying, Eventually(Equals(False))) |
1275 | |
1276 | """ Track is playing""" |
1277 | self.pointing_device.click_object(playbutton) |
1278 | - self.assertThat(self.main_view.isPlaying, Eventually(Equals(True))) |
1279 | + self.assertThat(self.player.isPlaying, Eventually(Equals(True))) |
1280 | |
1281 | def test_next_previous(self): |
1282 | """ Test going to next track (Music Library must exist) """ |
1283 | @@ -115,49 +115,49 @@ |
1284 | playbutton = self.main_view.get_now_playing_play_button() |
1285 | shufflebutton = self.main_view.get_shuffle_button() |
1286 | |
1287 | - title = lambda: self.main_view.currentTracktitle |
1288 | - artist = lambda: self.main_view.currentArtist |
1289 | + title = lambda: self.player.currentMetaTitle |
1290 | + artist = lambda: self.player.currentMetaArtist |
1291 | |
1292 | - orgTitle = self.main_view.currentTracktitle |
1293 | - orgArtist = self.main_view.currentArtist |
1294 | + orgTitle = self.player.currentMetaTitle |
1295 | + orgArtist = self.player.currentMetaArtist |
1296 | |
1297 | #check original track |
1298 | - self.assertThat(self.main_view.isPlaying, Eventually(Equals(True))) |
1299 | + self.assertThat(self.player.isPlaying, Eventually(Equals(True))) |
1300 | logger.debug("Original Song %s, %s" % (orgTitle, orgArtist)) |
1301 | |
1302 | """ Pause track """ |
1303 | self.pointing_device.click_object(playbutton) |
1304 | - self.assertThat(self.main_view.isPlaying, Eventually(Equals(False))) |
1305 | + self.assertThat(self.player.isPlaying, Eventually(Equals(False))) |
1306 | |
1307 | #ensure shuffle is off |
1308 | - if self.main_view.random: |
1309 | + if self.player.shuffle: |
1310 | logger.debug("Turning off shuffle") |
1311 | self.pointing_device.click_object(shufflebutton) |
1312 | else: |
1313 | logger.debug("Shuffle already off") |
1314 | - self.assertThat(self.main_view.random, Eventually(Equals(False))) |
1315 | + self.assertThat(self.player.shuffle, Eventually(Equals(False))) |
1316 | |
1317 | """ Select next """ |
1318 | #goal is to go back and forth and ensure 2 different songs |
1319 | forwardbutton = self.main_view.get_forward_button() |
1320 | self.pointing_device.click_object(forwardbutton) |
1321 | - self.assertThat(self.main_view.isPlaying, Eventually(Equals(True))) |
1322 | + self.assertThat(self.player.isPlaying, Eventually(Equals(True))) |
1323 | |
1324 | #ensure different song |
1325 | self.assertThat(title, Eventually(NotEquals(orgTitle))) |
1326 | self.assertThat(artist, Eventually(NotEquals(orgArtist))) |
1327 | - nextTitle = self.main_view.currentTracktitle |
1328 | - nextArtist = self.main_view.currentArtist |
1329 | + nextTitle = self.player.currentMetaTitle |
1330 | + nextArtist = self.player.currentMetaArtist |
1331 | logger.debug("Next Song %s, %s" % (nextTitle, nextArtist)) |
1332 | |
1333 | """ Pause track """ |
1334 | self.pointing_device.click_object(playbutton) |
1335 | - self.assertThat(self.main_view.isPlaying, Eventually(Equals(False))) |
1336 | + self.assertThat(self.player.isPlaying, Eventually(Equals(False))) |
1337 | |
1338 | """ Select previous """ |
1339 | previousbutton = self.main_view.get_previous_button() |
1340 | self.pointing_device.click_object(previousbutton) |
1341 | - self.assertThat(self.main_view.isPlaying, Eventually(Equals(True))) |
1342 | + self.assertThat(self.player.isPlaying, Eventually(Equals(True))) |
1343 | |
1344 | #ensure we're back to original song |
1345 | self.assertThat(title, Eventually(Equals(orgTitle))) |
1346 | @@ -176,19 +176,19 @@ |
1347 | playbutton = self.main_view.get_now_playing_play_button() |
1348 | shufflebutton = self.main_view.get_shuffle_button() |
1349 | |
1350 | - title = self.main_view.currentTracktitle |
1351 | - artist = self.main_view.currentArtist |
1352 | + title = self.player.currentMetaTitle |
1353 | + artist = self.player.currentMetaArtist |
1354 | |
1355 | #ensure track is playing |
1356 | - self.assertThat(self.main_view.isPlaying, Eventually(Equals(True))) |
1357 | + self.assertThat(self.player.isPlaying, Eventually(Equals(True))) |
1358 | |
1359 | #ensure shuffle is off |
1360 | - if self.main_view.random: |
1361 | + if self.player.shuffle: |
1362 | logger.debug("Turning off shuffle") |
1363 | self.pointing_device.click_object(shufflebutton) |
1364 | else: |
1365 | logger.debug("Shuffle already off") |
1366 | - self.assertThat(self.main_view.random, Eventually(Equals(False))) |
1367 | + self.assertThat(self.player.shuffle, Eventually(Equals(False))) |
1368 | |
1369 | """ Track is playing """ |
1370 | count = 1 |
1371 | @@ -200,25 +200,25 @@ |
1372 | |
1373 | """ Pause track """ |
1374 | self.pointing_device.click_object(playbutton) |
1375 | - self.assertThat(self.main_view.isPlaying, |
1376 | + self.assertThat(self.player.isPlaying, |
1377 | Eventually(Equals(False))) |
1378 | |
1379 | """ Select next """ |
1380 | forwardbutton = self.main_view.get_forward_button() |
1381 | self.pointing_device.click_object(forwardbutton) |
1382 | - self.assertThat(self.main_view.isPlaying, Eventually(Equals(True))) |
1383 | + self.assertThat(self.player.isPlaying, Eventually(Equals(True))) |
1384 | |
1385 | - title = self.main_view.currentTracktitle |
1386 | - artist = self.main_view.currentArtist |
1387 | + title = self.player.currentMetaTitle |
1388 | + artist = self.player.currentMetaArtist |
1389 | logger.debug("Current Song %s, %s" % (title, artist)) |
1390 | - logger.debug("File found %s" % self.main_view.currentFile) |
1391 | + logger.debug("File found %s" % self.player.currentMetaFile) |
1392 | |
1393 | count = count + 1 |
1394 | |
1395 | #make sure mp3 plays |
1396 | - self.assertThat(self.main_view.currentFile.endswith("mp3"), |
1397 | + self.assertThat(self.player.source.endswith("mp3"), |
1398 | Equals(True)) |
1399 | - self.assertThat(self.main_view.isPlaying, Eventually(Equals(True))) |
1400 | + self.assertThat(self.player.isPlaying, Eventually(Equals(True))) |
1401 | |
1402 | def test_shuffle(self): |
1403 | """ Test shuffle (Music Library must exist) """ |
1404 | @@ -237,16 +237,16 @@ |
1405 | previousbutton = self.main_view.get_previous_button() |
1406 | |
1407 | #play for a second, then pause |
1408 | - if not self.main_view.isPlaying: |
1409 | + if not self.player.isPlaying: |
1410 | logger.debug("Play not selected") |
1411 | self.pointing_device.click_object(playbutton) |
1412 | else: |
1413 | logger.debug("Already playing") |
1414 | |
1415 | - self.assertThat(self.main_view.isPlaying, Eventually(Equals(True))) |
1416 | + self.assertThat(self.player.isPlaying, Eventually(Equals(True))) |
1417 | time.sleep(1) |
1418 | self.pointing_device.click_object(playbutton) |
1419 | - self.assertThat(self.main_view.isPlaying, Eventually(Equals(False))) |
1420 | + self.assertThat(self.player.isPlaying, Eventually(Equals(False))) |
1421 | |
1422 | count = 0 |
1423 | while True: |
1424 | @@ -257,47 +257,47 @@ |
1425 | #this means a true shuffle happened |
1426 | #if it doesn't try again, up to count times |
1427 | |
1428 | - orgTitle = self.main_view.currentTracktitle |
1429 | - orgArtist = self.main_view.currentArtist |
1430 | + orgTitle = self.player.currentMetaTitle |
1431 | + orgArtist = self.player.currentMetaArtist |
1432 | logger.debug("Original Song %s, %s" % (orgTitle, orgArtist)) |
1433 | |
1434 | if (not self.main_view.toolbarShown): |
1435 | self.main_view.show_toolbar() |
1436 | |
1437 | #ensure shuffle is on |
1438 | - if not self.main_view.random: |
1439 | + if not self.player.shuffle: |
1440 | logger.debug("Turning on shuffle") |
1441 | self.pointing_device.click_object(shufflebutton) |
1442 | else: |
1443 | logger.debug("Shuffle already on") |
1444 | - self.assertThat(self.main_view.random, Eventually(Equals(True))) |
1445 | + self.assertThat(self.player.shuffle, Eventually(Equals(True))) |
1446 | |
1447 | self.pointing_device.click_object(forwardbutton) |
1448 | - self.assertThat(self.main_view.isPlaying, |
1449 | + self.assertThat(self.player.isPlaying, |
1450 | Eventually(Equals(True))) |
1451 | - title = self.main_view.currentTracktitle |
1452 | - artist = self.main_view.currentArtist |
1453 | + title = self.player.currentMetaTitle |
1454 | + artist = self.player.currentMetaArtist |
1455 | logger.debug("Current Song %s, %s" % (title, artist)) |
1456 | |
1457 | #go back to previous and check against original |
1458 | #play song, then pause before switching |
1459 | time.sleep(1) |
1460 | self.pointing_device.click_object(playbutton) |
1461 | - self.assertThat(self.main_view.isPlaying, |
1462 | + self.assertThat(self.player.isPlaying, |
1463 | Eventually(Equals(False))) |
1464 | |
1465 | #ensure shuffle is off |
1466 | - if self.main_view.random: |
1467 | + if self.player.shuffle: |
1468 | logger.debug("Turning off shuffle") |
1469 | self.pointing_device.click_object(shufflebutton) |
1470 | else: |
1471 | logger.debug("Shuffle already off") |
1472 | - self.assertThat(self.main_view.random, Eventually(Equals(False))) |
1473 | + self.assertThat(self.player.shuffle, Eventually(Equals(False))) |
1474 | |
1475 | self.pointing_device.click_object(previousbutton) |
1476 | |
1477 | - title = self.main_view.currentTracktitle |
1478 | - artist = self.main_view.currentArtist |
1479 | + title = self.player.currentMetaTitle |
1480 | + artist = self.player.currentMetaArtist |
1481 | |
1482 | if title != orgTitle and artist != orgArtist: |
1483 | #we shuffled properly |
1484 | @@ -362,9 +362,9 @@ |
1485 | self.assertThat(endtracksCount, Equals(initialtracksCount + 1)) |
1486 | |
1487 | #Assert that the song added to the list is not playing |
1488 | - self.assertThat(self.main_view.currentIndex, |
1489 | + self.assertThat(self.player.currentIndex, |
1490 | Eventually(NotEquals(endtracksCount))) |
1491 | - self.assertThat(self.main_view.isPlaying, Eventually(Equals(False))) |
1492 | + self.assertThat(self.player.isPlaying, Eventually(Equals(False))) |
1493 | |
1494 | #verify song's metadata matches the item added to the Now Playing view |
1495 | queueArtistName = self.main_view.get_queue_now_playing_artist( |
1496 | @@ -401,9 +401,9 @@ |
1497 | self.assertThat(endtracksCount, Equals(initialtracksCount + 3)) |
1498 | |
1499 | # Assert that the song added to the list is playing |
1500 | - self.assertThat(self.main_view.currentIndex, |
1501 | + self.assertThat(self.player.currentIndex, |
1502 | Eventually(NotEquals(endtracksCount))) |
1503 | - self.assertThat(self.main_view.isPlaying, Eventually(Equals(True))) |
1504 | + self.assertThat(self.player.isPlaying, Eventually(Equals(True))) |
1505 | |
1506 | # verify song's metadata matches the item added to the Now Playing view |
1507 | queueArtistName = self.main_view.get_queue_now_playing_artist( |
1508 | @@ -437,9 +437,9 @@ |
1509 | self.assertThat(endtracksCount, Equals(initialtracksCount + 1)) |
1510 | |
1511 | # Assert that the song added to the list is not playing |
1512 | - self.assertThat(self.main_view.currentIndex, |
1513 | + self.assertThat(self.player.currentIndex, |
1514 | Eventually(NotEquals(endtracksCount))) |
1515 | - self.assertThat(self.main_view.isPlaying, Eventually(Equals(False))) |
1516 | + self.assertThat(self.player.isPlaying, Eventually(Equals(False))) |
1517 | |
1518 | # verify song's metadata matches the item added to the Now Playing view |
1519 | queueArtistName = self.main_view.get_queue_now_playing_artist( |
1520 | @@ -534,9 +534,9 @@ |
1521 | self.assertThat(endtracksCount, Equals(initialtracksCount + 2)) |
1522 | |
1523 | # Assert that the song added to the list is playing |
1524 | - self.assertThat(self.main_view.currentIndex, |
1525 | + self.assertThat(self.player.currentIndex, |
1526 | Eventually(NotEquals(endtracksCount))) |
1527 | - self.assertThat(self.main_view.isPlaying, Eventually(Equals(True))) |
1528 | + self.assertThat(self.player.isPlaying, Eventually(Equals(True))) |
1529 | |
1530 | # verify song's metadata matches the item added to the Now Playing view |
1531 | queueArtistName = self.main_view.get_queue_now_playing_artist( |
FAILED: Continuous integration, rev:303 91.189. 93.70:8080/ job/music- app-ci/ 440/ 91.189. 93.70:8080/ job/generic- mediumtests- trusty/ 645 91.189. 93.70:8080/ job/music- app-raring- amd64-ci/ 440 91.189. 93.70:8080/ job/music- app-saucy- amd64-ci/ 442 91.189. 93.70:8080/ job/music- app-trusty- amd64-ci/ 161
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild: 91.189. 93.70:8080/ job/music- app-ci/ 440/rebuild
http://