Merge lp:~music-app-dev/music-app/prototype-now-playing-side-panel into lp:music-app/remix
- prototype-now-playing-side-panel
- Merge into remix
Status: | Superseded |
---|---|
Proposed branch: | lp:~music-app-dev/music-app/prototype-now-playing-side-panel |
Merge into: | lp:music-app/remix |
Diff against target: |
5322 lines (+2426/-1833) (has conflicts) 55 files modified
CMakeLists.txt (+13/-7) app/CMakeLists.txt (+10/-0) app/components/BlurredBackground.qml (+1/-1) app/components/CMakeLists.txt (+6/-2) app/components/CoverGrid.qml (+2/-2) app/components/Dialog/CMakeLists.txt (+4/-0) app/components/Dialog/ContentHubErrorDialog.qml (+38/-0) app/components/Dialog/ContentHubNotFoundDialog.qml (+46/-0) app/components/Dialog/ContentHubWaitDialog.qml (+37/-0) app/components/Dialog/EditPlaylistDialog.qml (+80/-0) app/components/Dialog/NewPlaylistDialog.qml (+75/-0) app/components/Dialog/RemovePlaylistDialog.qml (+59/-0) app/components/Flickables/CMakeLists.txt (+4/-0) app/components/Flickables/CardView.qml (+1/-0) app/components/Flickables/MultiSelectListView.qml (+51/-0) app/components/Flickables/MusicListView.qml (+32/-0) app/components/HeadState/CMakeLists.txt (+4/-0) app/components/HeadState/MultiSelectHeadState.qml (+108/-0) app/components/HeadState/PlaylistsHeadState.qml (+47/-0) app/components/HeadState/SearchableHeadState.qml (+34/-0) app/components/LibraryListModel.qml (+2/-2) app/components/ListItemActions/AddToPlaylist.qml (+2/-8) app/components/ListItemActions/AddToQueue.qml (+1/-1) app/components/MusicPage.qml (+2/-2) app/components/MusicRow.qml (+1/-1) app/components/MusicToolbar.qml (+244/-314) app/components/NowPlaying.qml (+550/-0) app/components/PlaylistsEmptyState.qml (+58/-0) app/components/ViewButton/CMakeLists.txt (+4/-0) app/components/ViewButton/PlayAllButton.qml (+34/-0) app/components/ViewButton/QueueAllButton.qml (+46/-0) app/components/ViewButton/ShuffleButton.qml (+46/-0) app/components/Walkthrough/Slide1.qml (+1/-1) app/components/Walkthrough/Slide2.qml (+1/-1) app/components/Walkthrough/Slide3.qml (+1/-1) app/components/Walkthrough/Walkthrough.qml (+1/-1) app/components/WorkerModelLoader.qml (+1/-1) app/logic/CMakeLists.txt (+4/-0) app/music-app.qml (+352/-155) app/ui/AddToPlaylist.qml (+22/-23) app/ui/Albums.qml (+22/-27) app/ui/ArtistView.qml (+29/-73) app/ui/Artists.qml (+19/-25) app/ui/CMakeLists.txt (+4/-0) app/ui/Genres.qml (+21/-26) app/ui/LibraryEmptyState.qml (+123/-0) app/ui/NowPlayingView.qml (+23/-624) app/ui/Playlists.qml (+31/-39) app/ui/Recent.qml (+18/-23) app/ui/Songs.qml (+23/-118) app/ui/SongsView.qml (+40/-283) click/CMakeLists.txt (+0/-15) tests/autopilot/music_app/__init__.py (+38/-44) tests/autopilot/music_app/tests/__init__.py (+2/-2) tests/autopilot/music_app/tests/test_music.py (+8/-11) Text conflict in app/music-app.qml |
To merge this branch: | bzr merge lp:~music-app-dev/music-app/prototype-now-playing-side-panel |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Music App Developers | Pending | ||
Review via email: mp+249143@code.launchpad.net |
This proposal has been superseded by a proposal from 2015-02-10.
Commit message
* Conditional layouts for the music app
Description of the change
DO NOT MERGE, just want to keep this MP to see a diff of what's been added.
- 842. By Victor Thompson
-
Add ItemLayout to the Layouts.
Unmerged revisions
- 842. By Victor Thompson
-
Add ItemLayout to the Layouts.
- 841. By Victor Thompson
-
start conditional layout prototype
- 840. By Andrew Hayzen
-
* Create generic MultiSelectList
View.qml for handling multiselect
* Create MusicListView.qml with our patches to ListView
* Move Flickables from components into their own Flickables folder.Approved by Victor Thompson, Ubuntu Phone Apps Jenkins Bot.
- 839. By Andrew Hayzen
-
* Do not allow LibraryEmptyState loader to be active if content-hub is running. Fixes: https:/
/bugs.launchpad .net/bugs/ 1418366. Approved by Victor Thompson, Ubuntu Phone Apps Jenkins Bot.
- 838. By Andrew Hayzen
-
* Move all Dialog components into their own files in components/Dialog.
Approved by Victor Thompson, Ubuntu Phone Apps Jenkins Bot.
- 837. By Andrew Hayzen
-
* Create common components for Play All, Queue All and Shuffle buttons within 'Views'.
Approved by Victor Thompson, Ubuntu Phone Apps Jenkins Bot.
- 836. By Andrew Hayzen
-
* Split EmptyStates into a page (for noMusic) and a component (for noPlaylists) and load in async.
Approved by Ubuntu Phone Apps Jenkins Bot, Victor Thompson.
- 835. By Andrew Hayzen
-
* Move existing head states into HeadState folder
* Create MultiSelectHeadState SearchableHeadState PlaylistHeadState
* Migrate AddToPlaylist Albums Artists Genres NowPlaying Playlists Songs SongsView to use the new HeadState.Approved by Ubuntu Phone Apps Jenkins Bot, Victor Thompson.
- 834. By Andrew Hayzen
-
* Make use of SDK PageStack.push(url, properties) instead of creating the component, object and pushing ourselves.
Approved by Victor Thompson, Ubuntu Phone Apps Jenkins Bot.
- 833. By Andrew Hayzen
-
* Rename common to components
* Move all qml components in components
* Move any JS scripts into logic.Approved by Ubuntu Phone Apps Jenkins Bot, Victor Thompson.
Preview Diff
1 | === modified file 'CMakeLists.txt' | |||
2 | --- CMakeLists.txt 2014-09-08 08:08:13 +0000 | |||
3 | +++ CMakeLists.txt 2015-02-10 03:13:44 +0000 | |||
4 | @@ -13,10 +13,10 @@ | |||
5 | 13 | set(DESKTOP_FILE "${PROJECT_NAME}_${APP_NAME}.desktop") | 13 | set(DESKTOP_FILE "${PROJECT_NAME}_${APP_NAME}.desktop") |
6 | 14 | set(URLS_FILE "${PROJECT_NAME}_${APP_NAME}.url-dispatcher") | 14 | set(URLS_FILE "${PROJECT_NAME}_${APP_NAME}.url-dispatcher") |
7 | 15 | set(APP_HARDCODE music-app) | 15 | set(APP_HARDCODE music-app) |
10 | 16 | set(MAIN_QML music-app.qml) | 16 | set(MAIN_QML app/music-app.qml) |
11 | 17 | set(ICON_FILE images/music-app@30.png) | 17 | set(ICON_FILE app/graphics/music-app@30.png) |
12 | 18 | set(AUTOPILOT_DIR music_app) | 18 | set(AUTOPILOT_DIR music_app) |
14 | 19 | set(UBUNTU_MANIFEST_PATH "click/manifest.json.in" CACHE INTERNAL "Tell QtCreator location and name of the manifest file") | 19 | set(UBUNTU_MANIFEST_PATH "manifest.json.in" CACHE INTERNAL "Tell QtCreator location and name of the manifest file") |
15 | 20 | 20 | ||
16 | 21 | if(CLICK_MODE) | 21 | if(CLICK_MODE) |
17 | 22 | if(NOT DEFINED BZR_SOURCE) | 22 | if(NOT DEFINED BZR_SOURCE) |
18 | @@ -30,6 +30,14 @@ | |||
19 | 30 | set(EXEC "qmlscene -qt5 ${MAIN_QML} --url=%u -I ./plugins") | 30 | set(EXEC "qmlscene -qt5 ${MAIN_QML} --url=%u -I ./plugins") |
20 | 31 | set(DESKTOP_DIR ${DATA_DIR}) | 31 | set(DESKTOP_DIR ${DATA_DIR}) |
21 | 32 | set(URLS_DIR ${DATA_DIR}) | 32 | set(URLS_DIR ${DATA_DIR}) |
22 | 33 | |||
23 | 34 | if(NOT BZR_REVNO) | ||
24 | 35 | set(BZR_REVNO "latest") | ||
25 | 36 | endif(NOT BZR_REVNO) | ||
26 | 37 | |||
27 | 38 | configure_file(manifest.json.in ${CMAKE_CURRENT_BINARY_DIR}/manifest.json) | ||
28 | 39 | install(FILES ${CMAKE_CURRENT_BINARY_DIR}/manifest.json apparmor.json | ||
29 | 40 | music-app-content.json DESTINATION ${CMAKE_INSTALL_PREFIX}) | ||
30 | 33 | else(CLICK_MODE) | 41 | else(CLICK_MODE) |
31 | 34 | set(DATA_DIR ${CMAKE_INSTALL_DATADIR}/${APP_HARDCODE}) | 42 | set(DATA_DIR ${CMAKE_INSTALL_DATADIR}/${APP_HARDCODE}) |
32 | 35 | set(EXEC ${APP_HARDCODE}) | 43 | set(EXEC ${APP_HARDCODE}) |
33 | @@ -53,7 +61,7 @@ | |||
34 | 53 | file(GLOB SRC_FILES | 61 | file(GLOB SRC_FILES |
35 | 54 | RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} | 62 | RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} |
36 | 55 | *.qml *.js *.png *.js *.json) | 63 | *.qml *.js *.png *.js *.json) |
38 | 56 | install(DIRECTORY common images DESTINATION ${DATA_DIR}) | 64 | install(DIRECTORY app DESTINATION ${DATA_DIR}) |
39 | 57 | install(FILES ${SRC_FILES} ${ICON_FILE} DESTINATION ${DATA_DIR}) | 65 | install(FILES ${SRC_FILES} ${ICON_FILE} DESTINATION ${DATA_DIR}) |
40 | 58 | 66 | ||
41 | 59 | configure_file(${DESKTOP_FILE}.in.in ${DESKTOP_FILE}.in) | 67 | configure_file(${DESKTOP_FILE}.in.in ${DESKTOP_FILE}.in) |
42 | @@ -71,9 +79,7 @@ | |||
43 | 71 | # Tests | 79 | # Tests |
44 | 72 | enable_testing() | 80 | enable_testing() |
45 | 73 | 81 | ||
49 | 74 | add_subdirectory(click) | 82 | add_subdirectory(app) |
47 | 75 | add_subdirectory(common) | ||
48 | 76 | add_subdirectory(images) | ||
50 | 77 | add_subdirectory(po) | 83 | add_subdirectory(po) |
51 | 78 | add_subdirectory(tests) | 84 | add_subdirectory(tests) |
52 | 79 | 85 | ||
53 | 80 | 86 | ||
54 | === added directory 'app' | |||
55 | === added file 'app/CMakeLists.txt' | |||
56 | --- app/CMakeLists.txt 1970-01-01 00:00:00 +0000 | |||
57 | +++ app/CMakeLists.txt 2015-02-10 03:13:44 +0000 | |||
58 | @@ -0,0 +1,10 @@ | |||
59 | 1 | add_subdirectory(components) | ||
60 | 2 | add_subdirectory(graphics) | ||
61 | 3 | add_subdirectory(logic) | ||
62 | 4 | add_subdirectory(ui) | ||
63 | 5 | |||
64 | 6 | # make the qml files visible on qtcreator | ||
65 | 7 | file(GLOB APP_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} | ||
66 | 8 | *.qml *.js *.png *.js *.json) | ||
67 | 9 | |||
68 | 10 | add_custom_target(com_ubuntu_music_APP_Files ALL SOURCES ${APP_FILES}) | ||
69 | 0 | 11 | ||
70 | === renamed directory 'common' => 'app/components' | |||
71 | === modified file 'app/components/BlurredBackground.qml' | |||
72 | --- common/BlurredBackground.qml 2014-11-11 02:46:42 +0000 | |||
73 | +++ app/components/BlurredBackground.qml 2015-02-10 03:13:44 +0000 | |||
74 | @@ -25,7 +25,7 @@ | |||
75 | 25 | Item { | 25 | Item { |
76 | 26 | width: parent.width | 26 | width: parent.width |
77 | 27 | 27 | ||
79 | 28 | property string art // : player.currentMetaFile === "" ? Qt.resolvedUrl("../images/music-app-cover@30.png") : player.currentMetaArt | 28 | property string art // : player.currentMetaFile === "" ? Qt.resolvedUrl("../graphics/music-app-cover@30.png") : player.currentMetaArt |
80 | 29 | 29 | ||
81 | 30 | // dark layer | 30 | // dark layer |
82 | 31 | Rectangle { | 31 | Rectangle { |
83 | 32 | 32 | ||
84 | === modified file 'app/components/CMakeLists.txt' | |||
85 | --- common/CMakeLists.txt 2015-01-20 17:47:30 +0000 | |||
86 | +++ app/components/CMakeLists.txt 2015-02-10 03:13:44 +0000 | |||
87 | @@ -1,7 +1,11 @@ | |||
88 | 1 | add_subdirectory(Dialog) | ||
89 | 2 | add_subdirectory(HeadState) | ||
90 | 3 | add_subdirectory(Flickables) | ||
91 | 1 | add_subdirectory(ListItemActions) | 4 | add_subdirectory(ListItemActions) |
92 | 5 | add_subdirectory(ViewButton) | ||
93 | 2 | add_subdirectory(Walkthrough) | 6 | add_subdirectory(Walkthrough) |
94 | 3 | 7 | ||
95 | 4 | # make the qml files visible on qtcreator | 8 | # make the qml files visible on qtcreator |
97 | 5 | file(GLOB COMMON_QML_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.qml) | 9 | file(GLOB COMPONENTS_QML_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.qml) |
98 | 6 | 10 | ||
100 | 7 | add_custom_target(com_ubuntu_music_COMMON_QMLFiles ALL SOURCES ${COMMON_QML_FILES}) | 11 | add_custom_target(com_ubuntu_music_COMPONENTS_QMLFiles ALL SOURCES ${COMPONENTS_QML_FILES}) |
101 | 8 | 12 | ||
102 | === modified file 'app/components/CoverGrid.qml' | |||
103 | --- common/CoverGrid.qml 2015-01-11 16:34:22 +0000 | |||
104 | +++ app/components/CoverGrid.qml 2015-02-10 03:13:44 +0000 | |||
105 | @@ -60,7 +60,7 @@ | |||
106 | 60 | ? (coverGrid.covers[index].art !== undefined | 60 | ? (coverGrid.covers[index].art !== undefined |
107 | 61 | ? coverGrid.covers[index].art | 61 | ? coverGrid.covers[index].art |
108 | 62 | : "image://albumart/artist=" + coverGrid.covers[index].author + "&album=" + coverGrid.covers[index].album) | 62 | : "image://albumart/artist=" + coverGrid.covers[index].author + "&album=" + coverGrid.covers[index].album) |
110 | 63 | : Qt.resolvedUrl("../images/music-app-cover@30.png") | 63 | : Qt.resolvedUrl("../graphics/music-app-cover@30.png") |
111 | 64 | 64 | ||
112 | 65 | // TODO: This should be investigated once http://pad.lv/1391368 | 65 | // TODO: This should be investigated once http://pad.lv/1391368 |
113 | 66 | // is resolved. Once it is, these can either be set to | 66 | // is resolved. Once it is, these can either be set to |
114 | @@ -73,7 +73,7 @@ | |||
115 | 73 | 73 | ||
116 | 74 | onStatusChanged: { | 74 | onStatusChanged: { |
117 | 75 | if (status === Image.Error) { | 75 | if (status === Image.Error) { |
119 | 76 | source = Qt.resolvedUrl("../images/music-app-cover@30.png") | 76 | source = Qt.resolvedUrl("../graphics/music-app-cover@30.png") |
120 | 77 | } else if (status === Image.Ready && index === 0) { | 77 | } else if (status === Image.Ready && index === 0) { |
121 | 78 | firstSource = source | 78 | firstSource = source |
122 | 79 | } | 79 | } |
123 | 80 | 80 | ||
124 | === added directory 'app/components/Dialog' | |||
125 | === added file 'app/components/Dialog/CMakeLists.txt' | |||
126 | --- app/components/Dialog/CMakeLists.txt 1970-01-01 00:00:00 +0000 | |||
127 | +++ app/components/Dialog/CMakeLists.txt 2015-02-10 03:13:44 +0000 | |||
128 | @@ -0,0 +1,4 @@ | |||
129 | 1 | # make the qml files visible on qtcreator | ||
130 | 2 | file(GLOB DIALOG_QML_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.qml) | ||
131 | 3 | |||
132 | 4 | add_custom_target(com_ubuntu_music_DIALOG_QMLFiles ALL SOURCES ${DIALOG_QML_FILES}) | ||
133 | 0 | 5 | ||
134 | === added file 'app/components/Dialog/ContentHubErrorDialog.qml' | |||
135 | --- app/components/Dialog/ContentHubErrorDialog.qml 1970-01-01 00:00:00 +0000 | |||
136 | +++ app/components/Dialog/ContentHubErrorDialog.qml 2015-02-10 03:13:44 +0000 | |||
137 | @@ -0,0 +1,38 @@ | |||
138 | 1 | /* | ||
139 | 2 | * Copyright (C) 2013, 2014, 2015 | ||
140 | 3 | * Andrew Hayzen <ahayzen@gmail.com> | ||
141 | 4 | * Daniel Holm <d.holmen@gmail.com> | ||
142 | 5 | * Victor Thompson <victor.thompson@gmail.com> | ||
143 | 6 | * | ||
144 | 7 | * This program is free software; you can redistribute it and/or modify | ||
145 | 8 | * it under the terms of the GNU General Public License as published by | ||
146 | 9 | * the Free Software Foundation; version 3. | ||
147 | 10 | * | ||
148 | 11 | * This program is distributed in the hope that it will be useful, | ||
149 | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
150 | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
151 | 14 | * GNU General Public License for more details. | ||
152 | 15 | * | ||
153 | 16 | * You should have received a copy of the GNU General Public License | ||
154 | 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
155 | 18 | */ | ||
156 | 19 | |||
157 | 20 | import QtQuick 2.3 | ||
158 | 21 | import Ubuntu.Components 1.1 | ||
159 | 22 | import Ubuntu.Components.Popups 1.0 | ||
160 | 23 | |||
161 | 24 | Dialog { | ||
162 | 25 | id: dialogContentHubError | ||
163 | 26 | |||
164 | 27 | property alias errorText: errorLabel.text | ||
165 | 28 | |||
166 | 29 | Label { | ||
167 | 30 | id: errorLabel | ||
168 | 31 | color: styleMusic.common.black | ||
169 | 32 | } | ||
170 | 33 | |||
171 | 34 | Button { | ||
172 | 35 | text: i18n.tr("OK") | ||
173 | 36 | onClicked: PopupUtils.close(dialogContentHubError) | ||
174 | 37 | } | ||
175 | 38 | } | ||
176 | 0 | 39 | ||
177 | === added file 'app/components/Dialog/ContentHubNotFoundDialog.qml' | |||
178 | --- app/components/Dialog/ContentHubNotFoundDialog.qml 1970-01-01 00:00:00 +0000 | |||
179 | +++ app/components/Dialog/ContentHubNotFoundDialog.qml 2015-02-10 03:13:44 +0000 | |||
180 | @@ -0,0 +1,46 @@ | |||
181 | 1 | /* | ||
182 | 2 | * Copyright (C) 2013, 2014, 2015 | ||
183 | 3 | * Andrew Hayzen <ahayzen@gmail.com> | ||
184 | 4 | * Daniel Holm <d.holmen@gmail.com> | ||
185 | 5 | * Victor Thompson <victor.thompson@gmail.com> | ||
186 | 6 | * | ||
187 | 7 | * This program is free software; you can redistribute it and/or modify | ||
188 | 8 | * it under the terms of the GNU General Public License as published by | ||
189 | 9 | * the Free Software Foundation; version 3. | ||
190 | 10 | * | ||
191 | 11 | * This program is distributed in the hope that it will be useful, | ||
192 | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
193 | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
194 | 14 | * GNU General Public License for more details. | ||
195 | 15 | * | ||
196 | 16 | * You should have received a copy of the GNU General Public License | ||
197 | 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
198 | 18 | */ | ||
199 | 19 | |||
200 | 20 | import QtQuick 2.3 | ||
201 | 21 | import Ubuntu.Components 1.1 | ||
202 | 22 | import Ubuntu.Components.Popups 1.0 | ||
203 | 23 | |||
204 | 24 | Dialog { | ||
205 | 25 | id: dialogContentHubNotFound | ||
206 | 26 | |||
207 | 27 | Label { | ||
208 | 28 | color: styleMusic.common.black | ||
209 | 29 | text: i18n.tr("Imported file not found") | ||
210 | 30 | } | ||
211 | 31 | |||
212 | 32 | Button { | ||
213 | 33 | text: i18n.tr("Wait") | ||
214 | 34 | onClicked: { | ||
215 | 35 | PopupUtils.close(dialogContentHubNotFound) | ||
216 | 36 | |||
217 | 37 | contentHubWaitForFile.dialog = PopupUtils.open(Qt.resolvedUrl("ContentHubWaitDialog.qml"), mainView) | ||
218 | 38 | contentHubWaitForFile.start(); | ||
219 | 39 | } | ||
220 | 40 | } | ||
221 | 41 | |||
222 | 42 | Button { | ||
223 | 43 | text: i18n.tr("Cancel") | ||
224 | 44 | onClicked: PopupUtils.close(dialogContentHubNotFound) | ||
225 | 45 | } | ||
226 | 46 | } | ||
227 | 0 | 47 | ||
228 | === added file 'app/components/Dialog/ContentHubWaitDialog.qml' | |||
229 | --- app/components/Dialog/ContentHubWaitDialog.qml 1970-01-01 00:00:00 +0000 | |||
230 | +++ app/components/Dialog/ContentHubWaitDialog.qml 2015-02-10 03:13:44 +0000 | |||
231 | @@ -0,0 +1,37 @@ | |||
232 | 1 | /* | ||
233 | 2 | * Copyright (C) 2013, 2014, 2015 | ||
234 | 3 | * Andrew Hayzen <ahayzen@gmail.com> | ||
235 | 4 | * Daniel Holm <d.holmen@gmail.com> | ||
236 | 5 | * Victor Thompson <victor.thompson@gmail.com> | ||
237 | 6 | * | ||
238 | 7 | * This program is free software; you can redistribute it and/or modify | ||
239 | 8 | * it under the terms of the GNU General Public License as published by | ||
240 | 9 | * the Free Software Foundation; version 3. | ||
241 | 10 | * | ||
242 | 11 | * This program is distributed in the hope that it will be useful, | ||
243 | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
244 | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
245 | 14 | * GNU General Public License for more details. | ||
246 | 15 | * | ||
247 | 16 | * You should have received a copy of the GNU General Public License | ||
248 | 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
249 | 18 | */ | ||
250 | 19 | |||
251 | 20 | import QtQuick 2.3 | ||
252 | 21 | import Ubuntu.Components 1.1 | ||
253 | 22 | import Ubuntu.Components.Popups 1.0 | ||
254 | 23 | import "../" | ||
255 | 24 | |||
256 | 25 | Dialog { | ||
257 | 26 | id: dialogContentHubWait | ||
258 | 27 | |||
259 | 28 | LoadingSpinnerComponent { | ||
260 | 29 | anchors { | ||
261 | 30 | horizontalCenter: parent.horizontalCenter | ||
262 | 31 | top: undefined | ||
263 | 32 | margins: units.gu(0) | ||
264 | 33 | } | ||
265 | 34 | loadingText: i18n.tr("Waiting for file(s)...") | ||
266 | 35 | visible: true | ||
267 | 36 | } | ||
268 | 37 | } | ||
269 | 0 | 38 | ||
270 | === added file 'app/components/Dialog/EditPlaylistDialog.qml' | |||
271 | --- app/components/Dialog/EditPlaylistDialog.qml 1970-01-01 00:00:00 +0000 | |||
272 | +++ app/components/Dialog/EditPlaylistDialog.qml 2015-02-10 03:13:44 +0000 | |||
273 | @@ -0,0 +1,80 @@ | |||
274 | 1 | /* | ||
275 | 2 | * Copyright (C) 2013, 2014, 2015 | ||
276 | 3 | * Andrew Hayzen <ahayzen@gmail.com> | ||
277 | 4 | * Daniel Holm <d.holmen@gmail.com> | ||
278 | 5 | * Victor Thompson <victor.thompson@gmail.com> | ||
279 | 6 | * | ||
280 | 7 | * This program is free software; you can redistribute it and/or modify | ||
281 | 8 | * it under the terms of the GNU General Public License as published by | ||
282 | 9 | * the Free Software Foundation; version 3. | ||
283 | 10 | * | ||
284 | 11 | * This program is distributed in the hope that it will be useful, | ||
285 | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
286 | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
287 | 14 | * GNU General Public License for more details. | ||
288 | 15 | * | ||
289 | 16 | * You should have received a copy of the GNU General Public License | ||
290 | 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
291 | 18 | */ | ||
292 | 19 | |||
293 | 20 | import QtQuick 2.3 | ||
294 | 21 | import Ubuntu.Components 1.1 | ||
295 | 22 | import Ubuntu.Components.Popups 1.0 | ||
296 | 23 | import QtQuick.LocalStorage 2.0 | ||
297 | 24 | import "../../logic/meta-database.js" as Library | ||
298 | 25 | import "../../logic/playlists.js" as Playlists | ||
299 | 26 | |||
300 | 27 | Dialog { | ||
301 | 28 | id: dialogEditPlaylist | ||
302 | 29 | // TRANSLATORS: this is a title of a dialog with a prompt to rename a playlist | ||
303 | 30 | title: i18n.tr("Rename playlist") | ||
304 | 31 | |||
305 | 32 | property string oldPlaylistName: "" | ||
306 | 33 | |||
307 | 34 | TextField { | ||
308 | 35 | id: playlistName | ||
309 | 36 | inputMethodHints: Qt.ImhNoPredictiveText | ||
310 | 37 | placeholderText: i18n.tr("Enter playlist name") | ||
311 | 38 | } | ||
312 | 39 | Label { | ||
313 | 40 | id: editplaylistoutput | ||
314 | 41 | color: "red" | ||
315 | 42 | visible: false | ||
316 | 43 | } | ||
317 | 44 | |||
318 | 45 | Button { | ||
319 | 46 | text: i18n.tr("Change") | ||
320 | 47 | color: styleMusic.dialog.confirmButtonColor | ||
321 | 48 | onClicked: { | ||
322 | 49 | editplaylistoutput.visible = true | ||
323 | 50 | |||
324 | 51 | if (playlistName.text.length > 0) { // make sure something is acually inputed | ||
325 | 52 | console.debug("Debug: User changed name from "+oldPlaylistName+" to "+playlistName.text) | ||
326 | 53 | |||
327 | 54 | if (Playlists.renamePlaylist(oldPlaylistName, playlistName.text) === true) { | ||
328 | 55 | |||
329 | 56 | if (Library.recentContainsPlaylist(oldPlaylistName)) { | ||
330 | 57 | Library.recentRenamePlaylist(oldPlaylistName, playlistName.text) | ||
331 | 58 | } | ||
332 | 59 | |||
333 | 60 | line2 = playlistName.text | ||
334 | 61 | |||
335 | 62 | playlistChangedHelper() // update recent/playlist models | ||
336 | 63 | |||
337 | 64 | PopupUtils.close(dialogEditPlaylist) | ||
338 | 65 | } | ||
339 | 66 | else { | ||
340 | 67 | editplaylistoutput.text = i18n.tr("Playlist already exists") | ||
341 | 68 | } | ||
342 | 69 | } | ||
343 | 70 | else { | ||
344 | 71 | editplaylistoutput.text = i18n.tr("Please type in a name.") | ||
345 | 72 | } | ||
346 | 73 | } | ||
347 | 74 | } | ||
348 | 75 | Button { | ||
349 | 76 | text: i18n.tr("Cancel") | ||
350 | 77 | color: styleMusic.dialog.cancelButtonColor | ||
351 | 78 | onClicked: PopupUtils.close(dialogEditPlaylist) | ||
352 | 79 | } | ||
353 | 80 | } | ||
354 | 0 | 81 | ||
355 | === added file 'app/components/Dialog/NewPlaylistDialog.qml' | |||
356 | --- app/components/Dialog/NewPlaylistDialog.qml 1970-01-01 00:00:00 +0000 | |||
357 | +++ app/components/Dialog/NewPlaylistDialog.qml 2015-02-10 03:13:44 +0000 | |||
358 | @@ -0,0 +1,75 @@ | |||
359 | 1 | /* | ||
360 | 2 | * Copyright (C) 2013, 2014, 2015 | ||
361 | 3 | * Andrew Hayzen <ahayzen@gmail.com> | ||
362 | 4 | * Daniel Holm <d.holmen@gmail.com> | ||
363 | 5 | * Victor Thompson <victor.thompson@gmail.com> | ||
364 | 6 | * | ||
365 | 7 | * This program is free software; you can redistribute it and/or modify | ||
366 | 8 | * it under the terms of the GNU General Public License as published by | ||
367 | 9 | * the Free Software Foundation; version 3. | ||
368 | 10 | * | ||
369 | 11 | * This program is distributed in the hope that it will be useful, | ||
370 | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
371 | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
372 | 14 | * GNU General Public License for more details. | ||
373 | 15 | * | ||
374 | 16 | * You should have received a copy of the GNU General Public License | ||
375 | 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
376 | 18 | */ | ||
377 | 19 | |||
378 | 20 | import QtQuick 2.3 | ||
379 | 21 | import Ubuntu.Components 1.1 | ||
380 | 22 | import Ubuntu.Components.Popups 1.0 | ||
381 | 23 | import QtQuick.LocalStorage 2.0 | ||
382 | 24 | import "../../logic/playlists.js" as Playlists | ||
383 | 25 | |||
384 | 26 | |||
385 | 27 | Dialog { | ||
386 | 28 | id: dialogNewPlaylist | ||
387 | 29 | objectName: "dialogNewPlaylist" | ||
388 | 30 | title: i18n.tr("New playlist") | ||
389 | 31 | TextField { | ||
390 | 32 | id: playlistName | ||
391 | 33 | objectName: "playlistNameTextField" | ||
392 | 34 | placeholderText: i18n.tr("Enter playlist name") | ||
393 | 35 | inputMethodHints: Qt.ImhNoPredictiveText | ||
394 | 36 | } | ||
395 | 37 | Label { | ||
396 | 38 | id: newplaylistoutput | ||
397 | 39 | color: "red" | ||
398 | 40 | visible: false // should only be visible when an error is made. | ||
399 | 41 | } | ||
400 | 42 | |||
401 | 43 | Button { | ||
402 | 44 | text: i18n.tr("Create") | ||
403 | 45 | color: styleMusic.dialog.confirmButtonColor | ||
404 | 46 | objectName: "newPlaylistDialogCreateButton" | ||
405 | 47 | onClicked: { | ||
406 | 48 | newplaylistoutput.visible = false // make sure its hidden now if there was an error last time | ||
407 | 49 | if (playlistName.text.length > 0) { // make sure something is acually inputed | ||
408 | 50 | if (Playlists.addPlaylist(playlistName.text) === true) { | ||
409 | 51 | console.debug("Debug: User created a new playlist named: ", playlistName.text) | ||
410 | 52 | |||
411 | 53 | playlistModel.filterPlaylists(); // reload model | ||
412 | 54 | |||
413 | 55 | PopupUtils.close(dialogNewPlaylist) | ||
414 | 56 | } | ||
415 | 57 | else { | ||
416 | 58 | console.debug("Debug: Playlist already exists") | ||
417 | 59 | newplaylistoutput.visible = true | ||
418 | 60 | newplaylistoutput.text = i18n.tr("Playlist already exists") | ||
419 | 61 | } | ||
420 | 62 | } | ||
421 | 63 | else { | ||
422 | 64 | newplaylistoutput.visible = true | ||
423 | 65 | newplaylistoutput.text = i18n.tr("Please type in a name.") | ||
424 | 66 | } | ||
425 | 67 | } | ||
426 | 68 | } | ||
427 | 69 | |||
428 | 70 | Button { | ||
429 | 71 | text: i18n.tr("Cancel") | ||
430 | 72 | color: styleMusic.dialog.cancelButtonColor | ||
431 | 73 | onClicked: PopupUtils.close(dialogNewPlaylist) | ||
432 | 74 | } | ||
433 | 75 | } | ||
434 | 0 | 76 | ||
435 | === added file 'app/components/Dialog/RemovePlaylistDialog.qml' | |||
436 | --- app/components/Dialog/RemovePlaylistDialog.qml 1970-01-01 00:00:00 +0000 | |||
437 | +++ app/components/Dialog/RemovePlaylistDialog.qml 2015-02-10 03:13:44 +0000 | |||
438 | @@ -0,0 +1,59 @@ | |||
439 | 1 | /* | ||
440 | 2 | * Copyright (C) 2013, 2014, 2015 | ||
441 | 3 | * Andrew Hayzen <ahayzen@gmail.com> | ||
442 | 4 | * Daniel Holm <d.holmen@gmail.com> | ||
443 | 5 | * Victor Thompson <victor.thompson@gmail.com> | ||
444 | 6 | * | ||
445 | 7 | * This program is free software; you can redistribute it and/or modify | ||
446 | 8 | * it under the terms of the GNU General Public License as published by | ||
447 | 9 | * the Free Software Foundation; version 3. | ||
448 | 10 | * | ||
449 | 11 | * This program is distributed in the hope that it will be useful, | ||
450 | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
451 | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
452 | 14 | * GNU General Public License for more details. | ||
453 | 15 | * | ||
454 | 16 | * You should have received a copy of the GNU General Public License | ||
455 | 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
456 | 18 | */ | ||
457 | 19 | |||
458 | 20 | import QtQuick 2.3 | ||
459 | 21 | import Ubuntu.Components 1.1 | ||
460 | 22 | import Ubuntu.Components.Popups 1.0 | ||
461 | 23 | import QtQuick.LocalStorage 2.0 | ||
462 | 24 | import "../../logic/meta-database.js" as Library | ||
463 | 25 | import "../../logic/playlists.js" as Playlists | ||
464 | 26 | |||
465 | 27 | Dialog { | ||
466 | 28 | id: dialogRemovePlaylist | ||
467 | 29 | // TRANSLATORS: this is a title of a dialog with a prompt to delete a playlist | ||
468 | 30 | title: i18n.tr("Permanently delete playlist?") | ||
469 | 31 | text: "("+i18n.tr("This cannot be undone")+")" | ||
470 | 32 | |||
471 | 33 | property string oldPlaylistName | ||
472 | 34 | |||
473 | 35 | Button { | ||
474 | 36 | text: i18n.tr("Remove") | ||
475 | 37 | color: styleMusic.dialog.confirmRemoveButtonColor | ||
476 | 38 | onClicked: { | ||
477 | 39 | // removing playlist | ||
478 | 40 | Playlists.removePlaylist(dialogRemovePlaylist.oldPlaylistName) | ||
479 | 41 | |||
480 | 42 | if (Library.recentContainsPlaylist(dialogRemovePlaylist.oldPlaylistName)) { | ||
481 | 43 | Library.recentRemovePlaylist(dialogRemovePlaylist.oldPlaylistName) | ||
482 | 44 | } | ||
483 | 45 | |||
484 | 46 | playlistChangedHelper(true) // update recent/playlist models | ||
485 | 47 | |||
486 | 48 | songStackPage.page = undefined | ||
487 | 49 | PopupUtils.close(dialogRemovePlaylist) | ||
488 | 50 | |||
489 | 51 | mainPageStack.goBack() | ||
490 | 52 | } | ||
491 | 53 | } | ||
492 | 54 | Button { | ||
493 | 55 | text: i18n.tr("Cancel") | ||
494 | 56 | color: styleMusic.dialog.cancelButtonColor | ||
495 | 57 | onClicked: PopupUtils.close(dialogRemovePlaylist) | ||
496 | 58 | } | ||
497 | 59 | } | ||
498 | 0 | 60 | ||
499 | === added directory 'app/components/Flickables' | |||
500 | === added file 'app/components/Flickables/CMakeLists.txt' | |||
501 | --- app/components/Flickables/CMakeLists.txt 1970-01-01 00:00:00 +0000 | |||
502 | +++ app/components/Flickables/CMakeLists.txt 2015-02-10 03:13:44 +0000 | |||
503 | @@ -0,0 +1,4 @@ | |||
504 | 1 | # make the qml files visible on qtcreator | ||
505 | 2 | file(GLOB FLICKABLES_QML_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.qml) | ||
506 | 3 | |||
507 | 4 | add_custom_target(com_ubuntu_music_FLICKABLES_QMLFiles ALL SOURCES ${FLICKABLES_QML_FILES}) | ||
508 | 0 | 5 | ||
509 | === renamed file 'common/CardView.qml' => 'app/components/Flickables/CardView.qml' | |||
510 | --- common/CardView.qml 2014-11-23 03:50:40 +0000 | |||
511 | +++ app/components/Flickables/CardView.qml 2015-02-10 03:13:44 +0000 | |||
512 | @@ -17,6 +17,7 @@ | |||
513 | 17 | 17 | ||
514 | 18 | import QtQuick 2.3 | 18 | import QtQuick 2.3 |
515 | 19 | import Ubuntu.Components 1.1 | 19 | import Ubuntu.Components 1.1 |
516 | 20 | import "../" | ||
517 | 20 | 21 | ||
518 | 21 | 22 | ||
519 | 22 | Flickable { | 23 | Flickable { |
520 | 23 | 24 | ||
521 | === added file 'app/components/Flickables/MultiSelectListView.qml' | |||
522 | --- app/components/Flickables/MultiSelectListView.qml 1970-01-01 00:00:00 +0000 | |||
523 | +++ app/components/Flickables/MultiSelectListView.qml 2015-02-10 03:13:44 +0000 | |||
524 | @@ -0,0 +1,51 @@ | |||
525 | 1 | /* | ||
526 | 2 | * Copyright (C) 2013, 2014, 2015 | ||
527 | 3 | * Andrew Hayzen <ahayzen@gmail.com> | ||
528 | 4 | * Daniel Holm <d.holmen@gmail.com> | ||
529 | 5 | * Victor Thompson <victor.thompson@gmail.com> | ||
530 | 6 | * | ||
531 | 7 | * This program is free software; you can redistribute it and/or modify | ||
532 | 8 | * it under the terms of the GNU General Public License as published by | ||
533 | 9 | * the Free Software Foundation; version 3. | ||
534 | 10 | * | ||
535 | 11 | * This program is distributed in the hope that it will be useful, | ||
536 | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
537 | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
538 | 14 | * GNU General Public License for more details. | ||
539 | 15 | * | ||
540 | 16 | * You should have received a copy of the GNU General Public License | ||
541 | 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
542 | 18 | */ | ||
543 | 19 | |||
544 | 20 | import QtQuick 2.3 | ||
545 | 21 | import Ubuntu.Components 1.1 | ||
546 | 22 | |||
547 | 23 | MusicListView { | ||
548 | 24 | property var selectedItems: [] | ||
549 | 25 | |||
550 | 26 | signal clearSelection() | ||
551 | 27 | signal closeSelection() | ||
552 | 28 | signal selectAll() | ||
553 | 29 | |||
554 | 30 | onClearSelection: selectedItems = [] | ||
555 | 31 | onCloseSelection: { | ||
556 | 32 | clearSelection() | ||
557 | 33 | state = "normal" | ||
558 | 34 | } | ||
559 | 35 | onSelectAll: { | ||
560 | 36 | var tmp = selectedItems | ||
561 | 37 | |||
562 | 38 | for (var i=0; i < model.count; i++) { | ||
563 | 39 | if (tmp.indexOf(i) === -1) { | ||
564 | 40 | tmp.push(i) | ||
565 | 41 | } | ||
566 | 42 | } | ||
567 | 43 | |||
568 | 44 | selectedItems = tmp | ||
569 | 45 | } | ||
570 | 46 | onVisibleChanged: { | ||
571 | 47 | if (!visible) { | ||
572 | 48 | closeSelection() | ||
573 | 49 | } | ||
574 | 50 | } | ||
575 | 51 | } | ||
576 | 0 | 52 | ||
577 | === added file 'app/components/Flickables/MusicListView.qml' | |||
578 | --- app/components/Flickables/MusicListView.qml 1970-01-01 00:00:00 +0000 | |||
579 | +++ app/components/Flickables/MusicListView.qml 2015-02-10 03:13:44 +0000 | |||
580 | @@ -0,0 +1,32 @@ | |||
581 | 1 | /* | ||
582 | 2 | * Copyright (C) 2013, 2014, 2015 | ||
583 | 3 | * Andrew Hayzen <ahayzen@gmail.com> | ||
584 | 4 | * Daniel Holm <d.holmen@gmail.com> | ||
585 | 5 | * Victor Thompson <victor.thompson@gmail.com> | ||
586 | 6 | * | ||
587 | 7 | * This program is free software; you can redistribute it and/or modify | ||
588 | 8 | * it under the terms of the GNU General Public License as published by | ||
589 | 9 | * the Free Software Foundation; version 3. | ||
590 | 10 | * | ||
591 | 11 | * This program is distributed in the hope that it will be useful, | ||
592 | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
593 | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
594 | 14 | * GNU General Public License for more details. | ||
595 | 15 | * | ||
596 | 16 | * You should have received a copy of the GNU General Public License | ||
597 | 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
598 | 18 | */ | ||
599 | 19 | |||
600 | 20 | import QtQuick 2.3 | ||
601 | 21 | import Ubuntu.Components 1.1 | ||
602 | 22 | |||
603 | 23 | |||
604 | 24 | ListView { | ||
605 | 25 | Component.onCompleted: { | ||
606 | 26 | // FIXME: workaround for qtubuntu not returning values depending on the grid unit definition | ||
607 | 27 | // for Flickable.maximumFlickVelocity and Flickable.flickDeceleration | ||
608 | 28 | var scaleFactor = units.gridUnit / 8; | ||
609 | 29 | maximumFlickVelocity = maximumFlickVelocity * scaleFactor; | ||
610 | 30 | flickDeceleration = flickDeceleration * scaleFactor; | ||
611 | 31 | } | ||
612 | 32 | } | ||
613 | 0 | 33 | ||
614 | === added directory 'app/components/HeadState' | |||
615 | === added file 'app/components/HeadState/CMakeLists.txt' | |||
616 | --- app/components/HeadState/CMakeLists.txt 1970-01-01 00:00:00 +0000 | |||
617 | +++ app/components/HeadState/CMakeLists.txt 2015-02-10 03:13:44 +0000 | |||
618 | @@ -0,0 +1,4 @@ | |||
619 | 1 | # make the qml files visible on qtcreator | ||
620 | 2 | file(GLOB HEAD_STATE_QML_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.qml) | ||
621 | 3 | |||
622 | 4 | add_custom_target(com_ubuntu_music_HEAD_STATE_QMLFiles ALL SOURCES ${HEAD_STATE_QML_FILES}) | ||
623 | 0 | 5 | ||
624 | === added file 'app/components/HeadState/MultiSelectHeadState.qml' | |||
625 | --- app/components/HeadState/MultiSelectHeadState.qml 1970-01-01 00:00:00 +0000 | |||
626 | +++ app/components/HeadState/MultiSelectHeadState.qml 2015-02-10 03:13:44 +0000 | |||
627 | @@ -0,0 +1,108 @@ | |||
628 | 1 | /* | ||
629 | 2 | * Copyright (C) 2015 | ||
630 | 3 | * Andrew Hayzen <ahayzen@gmail.com> | ||
631 | 4 | * Victor Thompson <victor.thompson@gmail.com> | ||
632 | 5 | * | ||
633 | 6 | * This program is free software; you can redistribute it and/or modify | ||
634 | 7 | * it under the terms of the GNU General Public License as published by | ||
635 | 8 | * the Free Software Foundation; version 3. | ||
636 | 9 | * | ||
637 | 10 | * This program is distributed in the hope that it will be useful, | ||
638 | 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
639 | 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
640 | 13 | * GNU General Public License for more details. | ||
641 | 14 | * | ||
642 | 15 | * You should have received a copy of the GNU General Public License | ||
643 | 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
644 | 17 | */ | ||
645 | 18 | |||
646 | 19 | import QtQuick 2.3 | ||
647 | 20 | import Ubuntu.Components 1.1 | ||
648 | 21 | |||
649 | 22 | PageHeadState { | ||
650 | 23 | id: selectionState | ||
651 | 24 | actions: [ | ||
652 | 25 | Action { | ||
653 | 26 | iconName: "select" | ||
654 | 27 | text: i18n.tr("Select All") | ||
655 | 28 | onTriggered: { | ||
656 | 29 | if (listview.selectedItems.length === listview.model.count) { | ||
657 | 30 | listview.clearSelection() | ||
658 | 31 | } else { | ||
659 | 32 | listview.selectAll() | ||
660 | 33 | } | ||
661 | 34 | } | ||
662 | 35 | }, | ||
663 | 36 | Action { | ||
664 | 37 | enabled: listview.selectedItems.length !== 0 | ||
665 | 38 | iconName: "add-to-playlist" | ||
666 | 39 | text: i18n.tr("Add to playlist") | ||
667 | 40 | onTriggered: { | ||
668 | 41 | var items = [] | ||
669 | 42 | |||
670 | 43 | for (var i=0; i < listview.selectedItems.length; i++) { | ||
671 | 44 | items.push(makeDict(listview.model.get(listview.selectedItems[i], listview.model.RoleModelData))); | ||
672 | 45 | } | ||
673 | 46 | |||
674 | 47 | mainPageStack.push(Qt.resolvedUrl("../../ui/AddToPlaylist.qml"), | ||
675 | 48 | {"chosenElements": items}) | ||
676 | 49 | |||
677 | 50 | listview.closeSelection() | ||
678 | 51 | } | ||
679 | 52 | }, | ||
680 | 53 | Action { | ||
681 | 54 | enabled: listview.selectedItems.length > 0 | ||
682 | 55 | iconName: "add" | ||
683 | 56 | text: i18n.tr("Add to queue") | ||
684 | 57 | visible: addToQueue | ||
685 | 58 | |||
686 | 59 | onTriggered: { | ||
687 | 60 | var items = [] | ||
688 | 61 | |||
689 | 62 | for (var i=0; i < listview.selectedItems.length; i++) { | ||
690 | 63 | items.push(listview.model.get(listview.selectedItems[i], listview.model.RoleModelData)); | ||
691 | 64 | } | ||
692 | 65 | |||
693 | 66 | trackQueue.appendList(items) | ||
694 | 67 | |||
695 | 68 | listview.closeSelection() | ||
696 | 69 | } | ||
697 | 70 | }, | ||
698 | 71 | Action { | ||
699 | 72 | enabled: listview.selectedItems.length > 0 | ||
700 | 73 | iconName: "delete" | ||
701 | 74 | text: i18n.tr("Delete") | ||
702 | 75 | visible: removable | ||
703 | 76 | |||
704 | 77 | onTriggered: { | ||
705 | 78 | removed(listview.selectedItems) | ||
706 | 79 | |||
707 | 80 | listview.closeSelection() | ||
708 | 81 | } | ||
709 | 82 | } | ||
710 | 83 | |||
711 | 84 | ] | ||
712 | 85 | backAction: Action { | ||
713 | 86 | text: i18n.tr("Cancel selection") | ||
714 | 87 | iconName: "back" | ||
715 | 88 | onTriggered: { | ||
716 | 89 | listview.clearSelection() | ||
717 | 90 | listview.state = "normal" | ||
718 | 91 | } | ||
719 | 92 | } | ||
720 | 93 | head: thisPage.head | ||
721 | 94 | name: "selection" | ||
722 | 95 | |||
723 | 96 | PropertyChanges { | ||
724 | 97 | target: thisPage.head | ||
725 | 98 | backAction: selectionState.backAction | ||
726 | 99 | actions: selectionState.actions | ||
727 | 100 | } | ||
728 | 101 | |||
729 | 102 | property bool addToQueue: true | ||
730 | 103 | property ListView listview | ||
731 | 104 | property bool removable: false | ||
732 | 105 | property Page thisPage | ||
733 | 106 | |||
734 | 107 | signal removed(var selectedItems) | ||
735 | 108 | } | ||
736 | 0 | 109 | ||
737 | === added file 'app/components/HeadState/PlaylistsHeadState.qml' | |||
738 | --- app/components/HeadState/PlaylistsHeadState.qml 1970-01-01 00:00:00 +0000 | |||
739 | +++ app/components/HeadState/PlaylistsHeadState.qml 2015-02-10 03:13:44 +0000 | |||
740 | @@ -0,0 +1,47 @@ | |||
741 | 1 | /* | ||
742 | 2 | * Copyright (C) 2015 | ||
743 | 3 | * Andrew Hayzen <ahayzen@gmail.com> | ||
744 | 4 | * Victor Thompson <victor.thompson@gmail.com> | ||
745 | 5 | * | ||
746 | 6 | * This program is free software; you can redistribute it and/or modify | ||
747 | 7 | * it under the terms of the GNU General Public License as published by | ||
748 | 8 | * the Free Software Foundation; version 3. | ||
749 | 9 | * | ||
750 | 10 | * This program is distributed in the hope that it will be useful, | ||
751 | 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
752 | 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
753 | 13 | * GNU General Public License for more details. | ||
754 | 14 | * | ||
755 | 15 | * You should have received a copy of the GNU General Public License | ||
756 | 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
757 | 17 | */ | ||
758 | 18 | |||
759 | 19 | import QtQuick 2.3 | ||
760 | 20 | import Ubuntu.Components 1.1 | ||
761 | 21 | import Ubuntu.Components.Popups 1.0 | ||
762 | 22 | |||
763 | 23 | |||
764 | 24 | PageHeadState { | ||
765 | 25 | name: "default" | ||
766 | 26 | head: thisPage.head | ||
767 | 27 | actions: [ | ||
768 | 28 | Action { | ||
769 | 29 | id: newPlaylistAction | ||
770 | 30 | objectName: "newPlaylistButton" | ||
771 | 31 | iconName: "add" | ||
772 | 32 | onTriggered: { | ||
773 | 33 | customdebug("New playlist.") | ||
774 | 34 | PopupUtils.open(Qt.resolvedUrl("../Dialog/NewPlaylistDialog.qml"), mainView) | ||
775 | 35 | } | ||
776 | 36 | }, | ||
777 | 37 | Action { | ||
778 | 38 | id: searchAction | ||
779 | 39 | iconName: "search" | ||
780 | 40 | onTriggered: thisPage.state = "search" | ||
781 | 41 | } | ||
782 | 42 | ] | ||
783 | 43 | |||
784 | 44 | property alias newPlaylistEnabled: newPlaylistAction.enabled | ||
785 | 45 | property alias searchEnabled: searchAction.enabled | ||
786 | 46 | property Page thisPage | ||
787 | 47 | } | ||
788 | 0 | 48 | ||
789 | === renamed file 'common/SearchHeadState.qml' => 'app/components/HeadState/SearchHeadState.qml' | |||
790 | === added file 'app/components/HeadState/SearchableHeadState.qml' | |||
791 | --- app/components/HeadState/SearchableHeadState.qml 1970-01-01 00:00:00 +0000 | |||
792 | +++ app/components/HeadState/SearchableHeadState.qml 2015-02-10 03:13:44 +0000 | |||
793 | @@ -0,0 +1,34 @@ | |||
794 | 1 | /* | ||
795 | 2 | * Copyright (C) 2015 | ||
796 | 3 | * Andrew Hayzen <ahayzen@gmail.com> | ||
797 | 4 | * Victor Thompson <victor.thompson@gmail.com> | ||
798 | 5 | * | ||
799 | 6 | * This program is free software; you can redistribute it and/or modify | ||
800 | 7 | * it under the terms of the GNU General Public License as published by | ||
801 | 8 | * the Free Software Foundation; version 3. | ||
802 | 9 | * | ||
803 | 10 | * This program is distributed in the hope that it will be useful, | ||
804 | 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
805 | 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
806 | 13 | * GNU General Public License for more details. | ||
807 | 14 | * | ||
808 | 15 | * You should have received a copy of the GNU General Public License | ||
809 | 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
810 | 17 | */ | ||
811 | 18 | |||
812 | 19 | import QtQuick 2.3 | ||
813 | 20 | import Ubuntu.Components 1.1 | ||
814 | 21 | |||
815 | 22 | |||
816 | 23 | PageHeadState { | ||
817 | 24 | name: "default" | ||
818 | 25 | head: thisPage.head | ||
819 | 26 | actions: Action { | ||
820 | 27 | id: searchAction | ||
821 | 28 | iconName: "search" | ||
822 | 29 | onTriggered: thisPage.state = "search" | ||
823 | 30 | } | ||
824 | 31 | |||
825 | 32 | property alias searchEnabled: searchAction.enabled | ||
826 | 33 | property Page thisPage | ||
827 | 34 | } | ||
828 | 0 | 35 | ||
829 | === renamed file 'LibraryListModel.qml' => 'app/components/LibraryListModel.qml' | |||
830 | --- LibraryListModel.qml 2015-01-20 23:58:27 +0000 | |||
831 | +++ app/components/LibraryListModel.qml 2015-02-10 03:13:44 +0000 | |||
832 | @@ -19,8 +19,8 @@ | |||
833 | 19 | 19 | ||
834 | 20 | import QtQuick 2.3 | 20 | import QtQuick 2.3 |
835 | 21 | import QtQuick.LocalStorage 2.0 | 21 | import QtQuick.LocalStorage 2.0 |
838 | 22 | import "meta-database.js" as Library | 22 | import "../logic/meta-database.js" as Library |
839 | 23 | import "playlists.js" as Playlists | 23 | import "../logic/playlists.js" as Playlists |
840 | 24 | 24 | ||
841 | 25 | Item { | 25 | Item { |
842 | 26 | id: libraryListModelItem | 26 | id: libraryListModelItem |
843 | 27 | 27 | ||
844 | === modified file 'app/components/ListItemActions/AddToPlaylist.qml' | |||
845 | --- common/ListItemActions/AddToPlaylist.qml 2015-01-11 15:54:04 +0000 | |||
846 | +++ app/components/ListItemActions/AddToPlaylist.qml 2015-02-10 03:13:44 +0000 | |||
847 | @@ -30,13 +30,7 @@ | |||
848 | 30 | onTriggered: { | 30 | onTriggered: { |
849 | 31 | console.debug("Debug: Add track to playlist"); | 31 | console.debug("Debug: Add track to playlist"); |
850 | 32 | 32 | ||
859 | 33 | var comp = Qt.createComponent("../../MusicaddtoPlaylist.qml") | 33 | mainPageStack.push(Qt.resolvedUrl("../../ui/AddToPlaylist.qml"), |
860 | 34 | var addToPlaylist = comp.createObject(mainPageStack, {"chosenElements": [makeDict(model)]}); | 34 | {"chosenElements": [makeDict(model)]}) |
853 | 35 | |||
854 | 36 | if (addToPlaylist == null) { // Error Handling | ||
855 | 37 | console.log("Error creating object"); | ||
856 | 38 | } | ||
857 | 39 | |||
858 | 40 | mainPageStack.push(addToPlaylist) | ||
861 | 41 | } | 35 | } |
862 | 42 | } | 36 | } |
863 | 43 | 37 | ||
864 | === modified file 'app/components/ListItemActions/AddToQueue.qml' | |||
865 | --- common/ListItemActions/AddToQueue.qml 2014-10-28 00:00:26 +0000 | |||
866 | +++ app/components/ListItemActions/AddToQueue.qml 2015-02-10 03:13:44 +0000 | |||
867 | @@ -19,7 +19,7 @@ | |||
868 | 19 | import QtQuick 2.3 | 19 | import QtQuick 2.3 |
869 | 20 | import QtQuick.LocalStorage 2.0 | 20 | import QtQuick.LocalStorage 2.0 |
870 | 21 | import Ubuntu.Components 1.1 | 21 | import Ubuntu.Components 1.1 |
872 | 22 | import "../../meta-database.js" as Library | 22 | import "../../logic/meta-database.js" as Library |
873 | 23 | 23 | ||
874 | 24 | Action { | 24 | Action { |
875 | 25 | iconName: "add" | 25 | iconName: "add" |
876 | 26 | 26 | ||
877 | === modified file 'app/components/MusicPage.qml' | |||
878 | --- common/MusicPage.qml 2015-01-10 19:22:08 +0000 | |||
879 | +++ app/components/MusicPage.qml 2015-02-10 03:13:44 +0000 | |||
880 | @@ -25,7 +25,7 @@ | |||
881 | 25 | Page { | 25 | Page { |
882 | 26 | id: thisPage | 26 | id: thisPage |
883 | 27 | anchors { | 27 | anchors { |
885 | 28 | bottomMargin: musicToolbar.visible ? musicToolbar.currentHeight : 0 | 28 | bottomMargin: musicToolbar.visible ? musicToolbar.height : 0 |
886 | 29 | fill: parent | 29 | fill: parent |
887 | 30 | } | 30 | } |
888 | 31 | 31 | ||
889 | @@ -56,7 +56,7 @@ | |||
890 | 56 | 56 | ||
891 | 57 | onVisibleChanged: { | 57 | onVisibleChanged: { |
892 | 58 | if (visible) { | 58 | if (visible) { |
894 | 59 | musicToolbar.setPage(thisPage); | 59 | mainPageStack.setPage(thisPage); |
895 | 60 | } | 60 | } |
896 | 61 | } | 61 | } |
897 | 62 | } | 62 | } |
898 | 63 | 63 | ||
899 | === modified file 'app/components/MusicRow.qml' | |||
900 | --- common/MusicRow.qml 2014-10-23 17:40:04 +0000 | |||
901 | +++ app/components/MusicRow.qml 2015-02-10 03:13:44 +0000 | |||
902 | @@ -55,7 +55,7 @@ | |||
903 | 55 | 55 | ||
904 | 56 | onStatusChanged: { | 56 | onStatusChanged: { |
905 | 57 | if (status === Image.Error) { | 57 | if (status === Image.Error) { |
907 | 58 | source = Qt.resolvedUrl("../images/music-app-cover@30.png") | 58 | source = Qt.resolvedUrl("../graphics/music-app-cover@30.png") |
908 | 59 | } | 59 | } |
909 | 60 | } | 60 | } |
910 | 61 | visible: imageSource !== undefined | 61 | visible: imageSource !== undefined |
911 | 62 | 62 | ||
912 | === renamed file 'MusicToolbar.qml' => 'app/components/MusicToolbar.qml' | |||
913 | --- MusicToolbar.qml 2015-01-23 07:22:52 +0000 | |||
914 | +++ app/components/MusicToolbar.qml 2015-02-10 03:13:44 +0000 | |||
915 | @@ -18,335 +18,265 @@ | |||
916 | 18 | */ | 18 | */ |
917 | 19 | 19 | ||
918 | 20 | import QtQuick 2.3 | 20 | import QtQuick 2.3 |
919 | 21 | import QtQuick.LocalStorage 2.0 | ||
920 | 22 | import QtMultimedia 5.0 | 21 | import QtMultimedia 5.0 |
921 | 23 | import Ubuntu.Components 1.1 | 22 | import Ubuntu.Components 1.1 |
922 | 24 | import Ubuntu.Components.Popups 1.0 | ||
923 | 25 | import "common" | ||
924 | 26 | 23 | ||
926 | 27 | Item { | 24 | Rectangle { |
927 | 28 | anchors { | 25 | anchors { |
928 | 29 | bottom: parent.bottom | 26 | bottom: parent.bottom |
929 | 30 | left: parent.left | 27 | left: parent.left |
930 | 31 | right: parent.right | 28 | right: parent.right |
931 | 32 | } | 29 | } |
986 | 33 | 30 | color: styleMusic.common.black | |
987 | 34 | // Properties storing the current page info | 31 | height: units.gu(7.25) |
988 | 35 | property var currentPage: null | 32 | objectName: "musicToolbarObject" |
989 | 36 | property var currentTab: null | 33 | |
990 | 37 | 34 | // Hack for autopilot otherwise MusicToolbar appears as QQuickRectangle | |
991 | 38 | // Properties and signals for the toolbar | 35 | // due to bug 1341671 it is required that there is a property so that |
992 | 39 | property alias currentHeight: musicToolbarPanel.height | 36 | // qml doesn't optimise using the parent type |
993 | 40 | property alias opened: musicToolbarPanel.opened | 37 | property bool bug1341671workaround: true |
994 | 41 | 38 | ||
995 | 42 | property bool popping: false | 39 | /* Toolbar controls */ |
996 | 43 | 40 | Item { | |
997 | 44 | /* Helper functions */ | 41 | id: toolbarControls |
944 | 45 | |||
945 | 46 | // Back button has been pressed, jump up pageStack or back to parent page | ||
946 | 47 | function goBack() | ||
947 | 48 | { | ||
948 | 49 | if (mainPageStack !== null && mainPageStack.depth > 1) { | ||
949 | 50 | mainPageStack.pop(currentPage) | ||
950 | 51 | } | ||
951 | 52 | } | ||
952 | 53 | |||
953 | 54 | // Pop a specific page in the stack | ||
954 | 55 | function popPage(page) | ||
955 | 56 | { | ||
956 | 57 | var tmpPages = [] | ||
957 | 58 | |||
958 | 59 | popping = true | ||
959 | 60 | |||
960 | 61 | while (mainPageStack.currentPage !== page && mainPageStack.depth > 0) { | ||
961 | 62 | tmpPages.push(mainPageStack.currentPage) | ||
962 | 63 | mainPageStack.pop() | ||
963 | 64 | } | ||
964 | 65 | |||
965 | 66 | if (mainPageStack.depth > 0) { | ||
966 | 67 | mainPageStack.pop() | ||
967 | 68 | } | ||
968 | 69 | |||
969 | 70 | for (var i=tmpPages.length - 1; i > -1; i--) { | ||
970 | 71 | mainPageStack.push(tmpPages[i]) | ||
971 | 72 | } | ||
972 | 73 | |||
973 | 74 | popping = false | ||
974 | 75 | } | ||
975 | 76 | |||
976 | 77 | // Set the current page, and any parent/stacks | ||
977 | 78 | function setPage(childPage) | ||
978 | 79 | { | ||
979 | 80 | if (!popping) { | ||
980 | 81 | currentPage = childPage; | ||
981 | 82 | } | ||
982 | 83 | } | ||
983 | 84 | |||
984 | 85 | Panel { | ||
985 | 86 | id: musicToolbarPanel | ||
998 | 87 | anchors { | 42 | anchors { |
1013 | 88 | left: parent.left | 43 | fill: parent |
1014 | 89 | right: parent.right | 44 | } |
1015 | 90 | bottom: parent.bottom | 45 | state: trackQueue.model.count === 0 ? "disabled" : "enabled" |
1016 | 91 | } | 46 | states: [ |
1017 | 92 | height: units.gu(7.25) | 47 | State { |
1018 | 93 | locked: true | 48 | name: "disabled" |
1019 | 94 | opened: true | 49 | PropertyChanges { |
1020 | 95 | 50 | target: disabledPlayerControlsGroup | |
1021 | 96 | /* Expanded toolbar */ | 51 | visible: true |
1022 | 97 | Item { | 52 | } |
1023 | 98 | id: musicToolbarExpandedContainer | 53 | PropertyChanges { |
1024 | 99 | anchors { | 54 | target: enabledPlayerControlsGroup |
1025 | 100 | fill: parent | 55 | visible: false |
1026 | 101 | } | 56 | } |
1027 | 57 | }, | ||
1028 | 58 | State { | ||
1029 | 59 | name: "enabled" | ||
1030 | 60 | PropertyChanges { | ||
1031 | 61 | target: disabledPlayerControlsGroup | ||
1032 | 62 | visible: false | ||
1033 | 63 | } | ||
1034 | 64 | PropertyChanges { | ||
1035 | 65 | target: enabledPlayerControlsGroup | ||
1036 | 66 | visible: true | ||
1037 | 67 | } | ||
1038 | 68 | } | ||
1039 | 69 | ] | ||
1040 | 70 | |||
1041 | 71 | /* Disabled (empty state) controls */ | ||
1042 | 72 | Item { | ||
1043 | 73 | id: disabledPlayerControlsGroup | ||
1044 | 74 | anchors { | ||
1045 | 75 | bottom: playerControlsProgressBar.top | ||
1046 | 76 | left: parent.left | ||
1047 | 77 | right: parent.right | ||
1048 | 78 | top: parent.top | ||
1049 | 79 | } | ||
1050 | 80 | |||
1051 | 81 | Label { | ||
1052 | 82 | id: noSongsInQueueLabel | ||
1053 | 83 | anchors { | ||
1054 | 84 | left: parent.left | ||
1055 | 85 | leftMargin: units.gu(2) | ||
1056 | 86 | right: disabledPlayerControlsPlayButton.left | ||
1057 | 87 | rightMargin: units.gu(2) | ||
1058 | 88 | verticalCenter: parent.verticalCenter | ||
1059 | 89 | } | ||
1060 | 90 | color: styleMusic.playerControls.labelColor | ||
1061 | 91 | text: i18n.tr("Tap to shuffle music") | ||
1062 | 92 | fontSize: "large" | ||
1063 | 93 | visible: !emptyPageLoader.noMusic | ||
1064 | 94 | wrapMode: Text.WordWrap | ||
1065 | 95 | maximumLineCount: 2 | ||
1066 | 96 | } | ||
1067 | 97 | |||
1068 | 98 | /* Play/Pause button */ | ||
1069 | 99 | Icon { | ||
1070 | 100 | id: disabledPlayerControlsPlayButton | ||
1071 | 101 | anchors { | ||
1072 | 102 | right: parent.right | ||
1073 | 103 | rightMargin: units.gu(3) | ||
1074 | 104 | verticalCenter: parent.verticalCenter | ||
1075 | 105 | } | ||
1076 | 106 | color: "#FFF" | ||
1077 | 107 | height: units.gu(2.5) | ||
1078 | 108 | name: player.playbackState === MediaPlayer.PlayingState ? | ||
1079 | 109 | "media-playback-pause" : "media-playback-start" | ||
1080 | 110 | objectName: "disabledSmallPlayShape" | ||
1081 | 111 | width: height | ||
1082 | 112 | } | ||
1083 | 113 | |||
1084 | 114 | /* Click to shuffle music */ | ||
1085 | 115 | MouseArea { | ||
1086 | 116 | anchors { | ||
1087 | 117 | fill: parent | ||
1088 | 118 | } | ||
1089 | 119 | onClicked: { | ||
1090 | 120 | if (emptyPageLoader.noMusic) { | ||
1091 | 121 | return; | ||
1092 | 122 | } | ||
1093 | 123 | |||
1094 | 124 | if (trackQueue.model.count === 0) { | ||
1095 | 125 | playRandomSong(); | ||
1096 | 126 | } | ||
1097 | 127 | else { | ||
1098 | 128 | player.toggle(); | ||
1099 | 129 | } | ||
1100 | 130 | } | ||
1101 | 131 | } | ||
1102 | 132 | } | ||
1103 | 133 | |||
1104 | 134 | /* Enabled (queue > 0) controls */ | ||
1105 | 135 | Item { | ||
1106 | 136 | id: enabledPlayerControlsGroup | ||
1107 | 137 | anchors { | ||
1108 | 138 | bottom: playerControlsProgressBar.top | ||
1109 | 139 | left: parent.left | ||
1110 | 140 | right: parent.right | ||
1111 | 141 | top: parent.top | ||
1112 | 142 | } | ||
1113 | 143 | |||
1114 | 144 | /* Album art in player controls */ | ||
1115 | 145 | CoverGrid { | ||
1116 | 146 | id: playerControlsImage | ||
1117 | 147 | anchors { | ||
1118 | 148 | bottom: parent.bottom | ||
1119 | 149 | left: parent.left | ||
1120 | 150 | top: parent.top | ||
1121 | 151 | } | ||
1122 | 152 | covers: [{art: player.currentMetaArt, author: player.currentMetaArtist, album: player.currentMetaArt}] | ||
1123 | 153 | size: parent.height | ||
1124 | 154 | } | ||
1125 | 155 | |||
1126 | 156 | /* Column of meta labels */ | ||
1127 | 157 | Column { | ||
1128 | 158 | id: playerControlsLabels | ||
1129 | 159 | anchors { | ||
1130 | 160 | left: playerControlsImage.right | ||
1131 | 161 | leftMargin: units.gu(1.5) | ||
1132 | 162 | right: playerControlsPlayButton.left | ||
1133 | 163 | rightMargin: units.gu(1) | ||
1134 | 164 | verticalCenter: parent.verticalCenter | ||
1135 | 165 | } | ||
1136 | 166 | |||
1137 | 167 | /* Title of track */ | ||
1138 | 168 | Label { | ||
1139 | 169 | id: playerControlsTitle | ||
1140 | 170 | anchors { | ||
1141 | 171 | left: parent.left | ||
1142 | 172 | right: parent.right | ||
1143 | 173 | } | ||
1144 | 174 | color: "#FFF" | ||
1145 | 175 | elide: Text.ElideRight | ||
1146 | 176 | fontSize: "small" | ||
1147 | 177 | font.weight: Font.DemiBold | ||
1148 | 178 | text: player.currentMetaTitle === "" | ||
1149 | 179 | ? player.source : player.currentMetaTitle | ||
1150 | 180 | } | ||
1151 | 181 | |||
1152 | 182 | /* Artist of track */ | ||
1153 | 183 | Label { | ||
1154 | 184 | id: playerControlsArtist | ||
1155 | 185 | anchors { | ||
1156 | 186 | left: parent.left | ||
1157 | 187 | right: parent.right | ||
1158 | 188 | } | ||
1159 | 189 | color: "#FFF" | ||
1160 | 190 | elide: Text.ElideRight | ||
1161 | 191 | fontSize: "small" | ||
1162 | 192 | opacity: 0.4 | ||
1163 | 193 | text: player.currentMetaArtist | ||
1164 | 194 | } | ||
1165 | 195 | } | ||
1166 | 196 | |||
1167 | 197 | /* Play/Pause button */ | ||
1168 | 198 | Icon { | ||
1169 | 199 | id: playerControlsPlayButton | ||
1170 | 200 | anchors { | ||
1171 | 201 | right: parent.right | ||
1172 | 202 | rightMargin: units.gu(3) | ||
1173 | 203 | verticalCenter: parent.verticalCenter | ||
1174 | 204 | } | ||
1175 | 205 | color: "#FFF" | ||
1176 | 206 | height: units.gu(2.5) | ||
1177 | 207 | name: player.playbackState === MediaPlayer.PlayingState ? | ||
1178 | 208 | "media-playback-pause" : "media-playback-start" | ||
1179 | 209 | objectName: "playShape" | ||
1180 | 210 | width: height | ||
1181 | 211 | } | ||
1182 | 212 | |||
1183 | 213 | /* Mouse area to jump to now playing */ | ||
1184 | 214 | MouseArea { | ||
1185 | 215 | anchors { | ||
1186 | 216 | fill: parent | ||
1187 | 217 | } | ||
1188 | 218 | objectName: "jumpNowPlaying" | ||
1189 | 219 | |||
1190 | 220 | onClicked: tabs.pushNowPlaying() | ||
1191 | 221 | } | ||
1192 | 222 | |||
1193 | 223 | /* Mouse area for the play button (ontop of the jump to now playing) */ | ||
1194 | 224 | MouseArea { | ||
1195 | 225 | anchors { | ||
1196 | 226 | bottom: parent.bottom | ||
1197 | 227 | horizontalCenter: playerControlsPlayButton.horizontalCenter | ||
1198 | 228 | top: parent.top | ||
1199 | 229 | } | ||
1200 | 230 | onClicked: player.toggle() | ||
1201 | 231 | width: units.gu(8) | ||
1202 | 232 | |||
1203 | 233 | Rectangle { | ||
1204 | 234 | anchors { | ||
1205 | 235 | fill: parent | ||
1206 | 236 | } | ||
1207 | 237 | color: "#FFF" | ||
1208 | 238 | opacity: parent.pressed ? 0.1 : 0 | ||
1209 | 239 | |||
1210 | 240 | Behavior on opacity { | ||
1211 | 241 | UbuntuNumberAnimation { | ||
1212 | 242 | duration: UbuntuAnimation.FastDuration | ||
1213 | 243 | } | ||
1214 | 244 | } | ||
1215 | 245 | } | ||
1216 | 246 | } | ||
1217 | 247 | } | ||
1218 | 248 | |||
1219 | 249 | /* Object which provides the progress bar when toolbar is minimized */ | ||
1220 | 250 | Rectangle { | ||
1221 | 251 | id: playerControlsProgressBar | ||
1222 | 252 | anchors { | ||
1223 | 253 | bottom: parent.bottom | ||
1224 | 254 | left: parent.left | ||
1225 | 255 | right: parent.right | ||
1226 | 256 | } | ||
1227 | 257 | color: styleMusic.common.black | ||
1228 | 258 | height: units.gu(0.25) | ||
1229 | 102 | 259 | ||
1230 | 103 | Rectangle { | 260 | Rectangle { |
1232 | 104 | id: musicToolbarPlayerControls | 261 | id: playerControlsProgressBarHint |
1233 | 105 | anchors { | 262 | anchors { |
1474 | 106 | fill: parent | 263 | left: parent.left |
1475 | 107 | } | 264 | top: parent.top |
1476 | 108 | color: "#000" | 265 | } |
1477 | 109 | state: trackQueue.model.count === 0 ? "disabled" : "enabled" | 266 | color: UbuntuColors.blue |
1478 | 110 | states: [ | 267 | height: parent.height |
1479 | 111 | State { | 268 | width: player.duration > 0 ? (player.position / player.duration) * playerControlsProgressBar.width : 0 |
1480 | 112 | name: "disabled" | 269 | |
1481 | 113 | PropertyChanges { | 270 | Connections { |
1482 | 114 | target: disabledPlayerControlsGroup | 271 | target: player |
1483 | 115 | visible: true | 272 | onPositionChanged: { |
1484 | 116 | } | 273 | playerControlsProgressBarHint.width = (player.position / player.duration) * playerControlsProgressBar.width |
1485 | 117 | PropertyChanges { | 274 | } |
1486 | 118 | target: enabledPlayerControlsGroup | 275 | onStopped: { |
1487 | 119 | visible: false | 276 | playerControlsProgressBarHint.width = 0; |
1248 | 120 | } | ||
1249 | 121 | }, | ||
1250 | 122 | State { | ||
1251 | 123 | name: "enabled" | ||
1252 | 124 | PropertyChanges { | ||
1253 | 125 | target: disabledPlayerControlsGroup | ||
1254 | 126 | visible: false | ||
1255 | 127 | } | ||
1256 | 128 | PropertyChanges { | ||
1257 | 129 | target: enabledPlayerControlsGroup | ||
1258 | 130 | visible: true | ||
1259 | 131 | } | ||
1260 | 132 | } | ||
1261 | 133 | ] | ||
1262 | 134 | |||
1263 | 135 | /* Disabled (empty state) controls */ | ||
1264 | 136 | Item { | ||
1265 | 137 | id: disabledPlayerControlsGroup | ||
1266 | 138 | anchors { | ||
1267 | 139 | bottom: playerControlsProgressBar.top | ||
1268 | 140 | left: parent.left | ||
1269 | 141 | right: parent.right | ||
1270 | 142 | top: parent.top | ||
1271 | 143 | } | ||
1272 | 144 | |||
1273 | 145 | Label { | ||
1274 | 146 | id: noSongsInQueueLabel | ||
1275 | 147 | anchors { | ||
1276 | 148 | left: parent.left | ||
1277 | 149 | leftMargin: units.gu(2) | ||
1278 | 150 | right: disabledPlayerControlsPlayButton.left | ||
1279 | 151 | rightMargin: units.gu(2) | ||
1280 | 152 | verticalCenter: parent.verticalCenter | ||
1281 | 153 | } | ||
1282 | 154 | color: styleMusic.playerControls.labelColor | ||
1283 | 155 | text: i18n.tr("Tap to shuffle music") | ||
1284 | 156 | fontSize: "large" | ||
1285 | 157 | visible: !emptyPage.noMusic | ||
1286 | 158 | wrapMode: Text.WordWrap | ||
1287 | 159 | maximumLineCount: 2 | ||
1288 | 160 | } | ||
1289 | 161 | |||
1290 | 162 | /* Play/Pause button */ | ||
1291 | 163 | Icon { | ||
1292 | 164 | id: disabledPlayerControlsPlayButton | ||
1293 | 165 | anchors { | ||
1294 | 166 | right: parent.right | ||
1295 | 167 | rightMargin: units.gu(3) | ||
1296 | 168 | verticalCenter: parent.verticalCenter | ||
1297 | 169 | } | ||
1298 | 170 | color: "#FFF" | ||
1299 | 171 | height: units.gu(2.5) | ||
1300 | 172 | name: player.playbackState === MediaPlayer.PlayingState ? | ||
1301 | 173 | "media-playback-pause" : "media-playback-start" | ||
1302 | 174 | objectName: "disabledSmallPlayShape" | ||
1303 | 175 | width: height | ||
1304 | 176 | } | ||
1305 | 177 | |||
1306 | 178 | /* Click to shuffle music */ | ||
1307 | 179 | MouseArea { | ||
1308 | 180 | anchors { | ||
1309 | 181 | fill: parent | ||
1310 | 182 | } | ||
1311 | 183 | onClicked: { | ||
1312 | 184 | if (emptyPage.noMusic) { | ||
1313 | 185 | return; | ||
1314 | 186 | } | ||
1315 | 187 | |||
1316 | 188 | if (trackQueue.model.count === 0) { | ||
1317 | 189 | playRandomSong(); | ||
1318 | 190 | } | ||
1319 | 191 | else { | ||
1320 | 192 | player.toggle(); | ||
1321 | 193 | } | ||
1322 | 194 | } | ||
1323 | 195 | } | ||
1324 | 196 | } | ||
1325 | 197 | |||
1326 | 198 | /* Enabled (queue > 0) controls */ | ||
1327 | 199 | Item { | ||
1328 | 200 | id: enabledPlayerControlsGroup | ||
1329 | 201 | anchors { | ||
1330 | 202 | bottom: playerControlsProgressBar.top | ||
1331 | 203 | left: parent.left | ||
1332 | 204 | right: parent.right | ||
1333 | 205 | top: parent.top | ||
1334 | 206 | } | ||
1335 | 207 | |||
1336 | 208 | /* Album art in player controls */ | ||
1337 | 209 | CoverGrid { | ||
1338 | 210 | id: playerControlsImage | ||
1339 | 211 | anchors { | ||
1340 | 212 | bottom: parent.bottom | ||
1341 | 213 | left: parent.left | ||
1342 | 214 | top: parent.top | ||
1343 | 215 | } | ||
1344 | 216 | covers: [{art: player.currentMetaArt, author: player.currentMetaArtist, album: player.currentMetaArt}] | ||
1345 | 217 | size: parent.height | ||
1346 | 218 | } | ||
1347 | 219 | |||
1348 | 220 | /* Column of meta labels */ | ||
1349 | 221 | Column { | ||
1350 | 222 | id: playerControlsLabels | ||
1351 | 223 | anchors { | ||
1352 | 224 | left: playerControlsImage.right | ||
1353 | 225 | leftMargin: units.gu(1.5) | ||
1354 | 226 | right: playerControlsPlayButton.left | ||
1355 | 227 | rightMargin: units.gu(1) | ||
1356 | 228 | verticalCenter: parent.verticalCenter | ||
1357 | 229 | } | ||
1358 | 230 | |||
1359 | 231 | /* Title of track */ | ||
1360 | 232 | Label { | ||
1361 | 233 | id: playerControlsTitle | ||
1362 | 234 | anchors { | ||
1363 | 235 | left: parent.left | ||
1364 | 236 | right: parent.right | ||
1365 | 237 | } | ||
1366 | 238 | color: "#FFF" | ||
1367 | 239 | elide: Text.ElideRight | ||
1368 | 240 | fontSize: "small" | ||
1369 | 241 | font.weight: Font.DemiBold | ||
1370 | 242 | text: player.currentMetaTitle === "" | ||
1371 | 243 | ? player.source : player.currentMetaTitle | ||
1372 | 244 | } | ||
1373 | 245 | |||
1374 | 246 | /* Artist of track */ | ||
1375 | 247 | Label { | ||
1376 | 248 | id: playerControlsArtist | ||
1377 | 249 | anchors { | ||
1378 | 250 | left: parent.left | ||
1379 | 251 | right: parent.right | ||
1380 | 252 | } | ||
1381 | 253 | color: "#FFF" | ||
1382 | 254 | elide: Text.ElideRight | ||
1383 | 255 | fontSize: "small" | ||
1384 | 256 | opacity: 0.4 | ||
1385 | 257 | text: player.currentMetaArtist | ||
1386 | 258 | } | ||
1387 | 259 | } | ||
1388 | 260 | |||
1389 | 261 | /* Play/Pause button */ | ||
1390 | 262 | Icon { | ||
1391 | 263 | id: playerControlsPlayButton | ||
1392 | 264 | anchors { | ||
1393 | 265 | right: parent.right | ||
1394 | 266 | rightMargin: units.gu(3) | ||
1395 | 267 | verticalCenter: parent.verticalCenter | ||
1396 | 268 | } | ||
1397 | 269 | color: "#FFF" | ||
1398 | 270 | height: units.gu(2.5) | ||
1399 | 271 | name: player.playbackState === MediaPlayer.PlayingState ? | ||
1400 | 272 | "media-playback-pause" : "media-playback-start" | ||
1401 | 273 | objectName: "playShape" | ||
1402 | 274 | width: height | ||
1403 | 275 | } | ||
1404 | 276 | |||
1405 | 277 | MouseArea { | ||
1406 | 278 | anchors { | ||
1407 | 279 | bottom: parent.bottom | ||
1408 | 280 | horizontalCenter: playerControlsPlayButton.horizontalCenter | ||
1409 | 281 | top: parent.top | ||
1410 | 282 | } | ||
1411 | 283 | onClicked: player.toggle() | ||
1412 | 284 | width: units.gu(8) | ||
1413 | 285 | |||
1414 | 286 | Rectangle { | ||
1415 | 287 | anchors { | ||
1416 | 288 | fill: parent | ||
1417 | 289 | } | ||
1418 | 290 | color: "#FFF" | ||
1419 | 291 | opacity: parent.pressed ? 0.1 : 0 | ||
1420 | 292 | |||
1421 | 293 | Behavior on opacity { | ||
1422 | 294 | UbuntuNumberAnimation { | ||
1423 | 295 | duration: UbuntuAnimation.FastDuration | ||
1424 | 296 | } | ||
1425 | 297 | } | ||
1426 | 298 | } | ||
1427 | 299 | } | ||
1428 | 300 | |||
1429 | 301 | /* Mouse area to jump to now playing */ | ||
1430 | 302 | Item { | ||
1431 | 303 | anchors { | ||
1432 | 304 | bottom: parent.bottom | ||
1433 | 305 | left: parent.left | ||
1434 | 306 | right: playerControlsLabels.right | ||
1435 | 307 | top: parent.top | ||
1436 | 308 | } | ||
1437 | 309 | objectName: "jumpNowPlaying" | ||
1438 | 310 | function trigger() { | ||
1439 | 311 | tabs.pushNowPlaying(); | ||
1440 | 312 | } | ||
1441 | 313 | } | ||
1442 | 314 | } | ||
1443 | 315 | |||
1444 | 316 | /* Object which provides the progress bar when toolbar is minimized */ | ||
1445 | 317 | Rectangle { | ||
1446 | 318 | id: playerControlsProgressBar | ||
1447 | 319 | anchors { | ||
1448 | 320 | bottom: parent.bottom | ||
1449 | 321 | left: parent.left | ||
1450 | 322 | right: parent.right | ||
1451 | 323 | } | ||
1452 | 324 | color: styleMusic.common.black | ||
1453 | 325 | height: units.gu(0.25) | ||
1454 | 326 | |||
1455 | 327 | Rectangle { | ||
1456 | 328 | id: playerControlsProgressBarHint | ||
1457 | 329 | anchors { | ||
1458 | 330 | left: parent.left | ||
1459 | 331 | top: parent.top | ||
1460 | 332 | } | ||
1461 | 333 | color: UbuntuColors.blue | ||
1462 | 334 | height: parent.height | ||
1463 | 335 | width: player.duration > 0 ? (player.position / player.duration) * playerControlsProgressBar.width : 0 | ||
1464 | 336 | |||
1465 | 337 | Connections { | ||
1466 | 338 | target: player | ||
1467 | 339 | onPositionChanged: { | ||
1468 | 340 | playerControlsProgressBarHint.width = (player.position / player.duration) * playerControlsProgressBar.width | ||
1469 | 341 | } | ||
1470 | 342 | onStopped: { | ||
1471 | 343 | playerControlsProgressBarHint.width = 0; | ||
1472 | 344 | } | ||
1473 | 345 | } | ||
1488 | 346 | } | 277 | } |
1489 | 347 | } | 278 | } |
1490 | 348 | } | 279 | } |
1491 | 349 | } | 280 | } |
1492 | 350 | } | 281 | } |
1493 | 351 | } | 282 | } |
1494 | 352 | |||
1495 | 353 | 283 | ||
1496 | === added file 'app/components/NowPlaying.qml' | |||
1497 | --- app/components/NowPlaying.qml 1970-01-01 00:00:00 +0000 | |||
1498 | +++ app/components/NowPlaying.qml 2015-02-10 03:13:44 +0000 | |||
1499 | @@ -0,0 +1,550 @@ | |||
1500 | 1 | /* | ||
1501 | 2 | * Copyright (C) 2013, 2014, 2015 | ||
1502 | 3 | * Andrew Hayzen <ahayzen@gmail.com> | ||
1503 | 4 | * Daniel Holm <d.holmen@gmail.com> | ||
1504 | 5 | * Victor Thompson <victor.thompson@gmail.com> | ||
1505 | 6 | * | ||
1506 | 7 | * This program is free software; you can redistribute it and/or modify | ||
1507 | 8 | * it under the terms of the GNU General Public License as published by | ||
1508 | 9 | * the Free Software Foundation; version 3. | ||
1509 | 10 | * | ||
1510 | 11 | * This program is distributed in the hope that it will be useful, | ||
1511 | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
1512 | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
1513 | 14 | * GNU General Public License for more details. | ||
1514 | 15 | * | ||
1515 | 16 | * You should have received a copy of the GNU General Public License | ||
1516 | 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
1517 | 18 | */ | ||
1518 | 19 | |||
1519 | 20 | import QtMultimedia 5.0 | ||
1520 | 21 | import QtQuick 2.3 | ||
1521 | 22 | import QtQuick.LocalStorage 2.0 | ||
1522 | 23 | import Ubuntu.Components 1.1 | ||
1523 | 24 | import Ubuntu.Thumbnailer 0.1 | ||
1524 | 25 | import "../components" | ||
1525 | 26 | import "../components/Flickables" | ||
1526 | 27 | import "../components/HeadState" | ||
1527 | 28 | import "../components/ListItemActions" | ||
1528 | 29 | import "../components/Themes/Ambiance" | ||
1529 | 30 | import "../logic/meta-database.js" as Library | ||
1530 | 31 | import "../logic/playlists.js" as Playlists | ||
1531 | 32 | |||
1532 | 33 | Item { | ||
1533 | 34 | id: nowPlayingView | ||
1534 | 35 | objectName: "nowPlayingView" | ||
1535 | 36 | |||
1536 | 37 | anchors { | ||
1537 | 38 | fill: parent | ||
1538 | 39 | } | ||
1539 | 40 | |||
1540 | 41 | property bool isListView: false | ||
1541 | 42 | |||
1542 | 43 | Item { | ||
1543 | 44 | id: fullview | ||
1544 | 45 | anchors { | ||
1545 | 46 | top: parent.top | ||
1546 | 47 | topMargin: mainView.header.height | ||
1547 | 48 | } | ||
1548 | 49 | height: parent.height - mainView.header.height - units.gu(9.5) | ||
1549 | 50 | visible: !isListView || wideAspect | ||
1550 | 51 | width: parent.width | ||
1551 | 52 | |||
1552 | 53 | BlurredBackground { | ||
1553 | 54 | id: blurredBackground | ||
1554 | 55 | anchors { | ||
1555 | 56 | left: parent.left | ||
1556 | 57 | right: parent.right | ||
1557 | 58 | top: parent.top | ||
1558 | 59 | } | ||
1559 | 60 | art: albumImage.firstSource | ||
1560 | 61 | height: parent.height - units.gu(7) | ||
1561 | 62 | |||
1562 | 63 | Item { | ||
1563 | 64 | id: albumImageContainer | ||
1564 | 65 | anchors { | ||
1565 | 66 | horizontalCenter: parent.horizontalCenter | ||
1566 | 67 | top: parent.top | ||
1567 | 68 | } | ||
1568 | 69 | height: parent.height | ||
1569 | 70 | width: parent.width | ||
1570 | 71 | |||
1571 | 72 | CoverGrid { | ||
1572 | 73 | id: albumImage | ||
1573 | 74 | anchors.centerIn: parent | ||
1574 | 75 | covers: [{art: player.currentMetaArt, author: player.currentMetaArtist, album: player.currentMetaAlbum}] | ||
1575 | 76 | size: parent.width > parent.height ? parent.height : parent.width | ||
1576 | 77 | } | ||
1577 | 78 | } | ||
1578 | 79 | |||
1579 | 80 | Rectangle { | ||
1580 | 81 | id: nowPlayingWideAspectLabelsBackground | ||
1581 | 82 | anchors.bottom: parent.bottom | ||
1582 | 83 | color: styleMusic.common.black | ||
1583 | 84 | height: nowPlayingWideAspectTitle.lineCount === 1 ? units.gu(10) : units.gu(13) | ||
1584 | 85 | opacity: 0.8 | ||
1585 | 86 | width: parent.width | ||
1586 | 87 | } | ||
1587 | 88 | |||
1588 | 89 | /* Column for labels in wideAspect */ | ||
1589 | 90 | Column { | ||
1590 | 91 | id: nowPlayingWideAspectLabels | ||
1591 | 92 | spacing: units.gu(1) | ||
1592 | 93 | anchors { | ||
1593 | 94 | left: parent.left | ||
1594 | 95 | leftMargin: units.gu(2) | ||
1595 | 96 | right: parent.right | ||
1596 | 97 | rightMargin: units.gu(2) | ||
1597 | 98 | top: nowPlayingWideAspectLabelsBackground.top | ||
1598 | 99 | topMargin: nowPlayingWideAspectTitle.lineCount === 1 ? units.gu(2) : units.gu(1.5) | ||
1599 | 100 | } | ||
1600 | 101 | |||
1601 | 102 | /* Title of track */ | ||
1602 | 103 | Label { | ||
1603 | 104 | id: nowPlayingWideAspectTitle | ||
1604 | 105 | anchors { | ||
1605 | 106 | left: parent.left | ||
1606 | 107 | leftMargin: units.gu(1) | ||
1607 | 108 | right: parent.right | ||
1608 | 109 | rightMargin: units.gu(1) | ||
1609 | 110 | } | ||
1610 | 111 | color: styleMusic.playerControls.labelColor | ||
1611 | 112 | elide: Text.ElideRight | ||
1612 | 113 | fontSize: "x-large" | ||
1613 | 114 | maximumLineCount: 2 | ||
1614 | 115 | objectName: "playercontroltitle" | ||
1615 | 116 | text: trackQueue.model.count === 0 ? "" : player.currentMetaTitle === "" ? player.currentMetaFile : player.currentMetaTitle | ||
1616 | 117 | wrapMode: Text.WordWrap | ||
1617 | 118 | } | ||
1618 | 119 | |||
1619 | 120 | /* Artist of track */ | ||
1620 | 121 | Label { | ||
1621 | 122 | id: nowPlayingWideAspectArtist | ||
1622 | 123 | anchors { | ||
1623 | 124 | left: parent.left | ||
1624 | 125 | leftMargin: units.gu(1) | ||
1625 | 126 | right: parent.right | ||
1626 | 127 | rightMargin: units.gu(1) | ||
1627 | 128 | } | ||
1628 | 129 | color: styleMusic.nowPlaying.labelSecondaryColor | ||
1629 | 130 | elide: Text.ElideRight | ||
1630 | 131 | fontSize: "small" | ||
1631 | 132 | text: trackQueue.model.count === 0 ? "" : player.currentMetaArtist | ||
1632 | 133 | } | ||
1633 | 134 | } | ||
1634 | 135 | |||
1635 | 136 | /* Detect cover art swipe */ | ||
1636 | 137 | MouseArea { | ||
1637 | 138 | anchors.fill: parent | ||
1638 | 139 | property string direction: "None" | ||
1639 | 140 | property real lastX: -1 | ||
1640 | 141 | |||
1641 | 142 | onPressed: lastX = mouse.x | ||
1642 | 143 | |||
1643 | 144 | onReleased: { | ||
1644 | 145 | var diff = mouse.x - lastX | ||
1645 | 146 | if (Math.abs(diff) < units.gu(4)) { | ||
1646 | 147 | return; | ||
1647 | 148 | } else if (diff < 0) { | ||
1648 | 149 | player.nextSong() | ||
1649 | 150 | } else if (diff > 0) { | ||
1650 | 151 | player.previousSong() | ||
1651 | 152 | } | ||
1652 | 153 | } | ||
1653 | 154 | } | ||
1654 | 155 | } | ||
1655 | 156 | |||
1656 | 157 | /* Background for progress bar component */ | ||
1657 | 158 | Rectangle { | ||
1658 | 159 | id: musicToolbarFullProgressBackground | ||
1659 | 160 | anchors { | ||
1660 | 161 | bottom: parent.bottom | ||
1661 | 162 | left: parent.left | ||
1662 | 163 | right: parent.right | ||
1663 | 164 | top: blurredBackground.bottom | ||
1664 | 165 | } | ||
1665 | 166 | color: styleMusic.common.black | ||
1666 | 167 | } | ||
1667 | 168 | |||
1668 | 169 | /* Progress bar component */ | ||
1669 | 170 | Item { | ||
1670 | 171 | id: musicToolbarFullProgressContainer | ||
1671 | 172 | anchors.left: parent.left | ||
1672 | 173 | anchors.leftMargin: units.gu(3) | ||
1673 | 174 | anchors.right: parent.right | ||
1674 | 175 | anchors.rightMargin: units.gu(3) | ||
1675 | 176 | anchors.top: blurredBackground.bottom | ||
1676 | 177 | anchors.topMargin: units.gu(1) | ||
1677 | 178 | height: units.gu(3) | ||
1678 | 179 | width: parent.width | ||
1679 | 180 | |||
1680 | 181 | /* Position label */ | ||
1681 | 182 | Label { | ||
1682 | 183 | id: musicToolbarFullPositionLabel | ||
1683 | 184 | anchors.top: progressSliderMusic.bottom | ||
1684 | 185 | anchors.topMargin: units.gu(-2) | ||
1685 | 186 | anchors.left: parent.left | ||
1686 | 187 | color: styleMusic.nowPlaying.labelSecondaryColor | ||
1687 | 188 | fontSize: "small" | ||
1688 | 189 | height: parent.height | ||
1689 | 190 | horizontalAlignment: Text.AlignHCenter | ||
1690 | 191 | text: durationToString(player.position) | ||
1691 | 192 | verticalAlignment: Text.AlignVCenter | ||
1692 | 193 | width: units.gu(3) | ||
1693 | 194 | } | ||
1694 | 195 | |||
1695 | 196 | Slider { | ||
1696 | 197 | id: progressSliderMusic | ||
1697 | 198 | anchors.left: parent.left | ||
1698 | 199 | anchors.right: parent.right | ||
1699 | 200 | maximumValue: player.duration // load value at startup | ||
1700 | 201 | objectName: "progressSliderShape" | ||
1701 | 202 | style: UbuntuBlueSliderStyle {} | ||
1702 | 203 | value: player.position // load value at startup | ||
1703 | 204 | |||
1704 | 205 | function formatValue(v) { | ||
1705 | 206 | if (seeking) { // update position label while dragging | ||
1706 | 207 | musicToolbarFullPositionLabel.text = durationToString(v) | ||
1707 | 208 | } | ||
1708 | 209 | |||
1709 | 210 | return durationToString(v) | ||
1710 | 211 | } | ||
1711 | 212 | |||
1712 | 213 | property bool seeking: false | ||
1713 | 214 | property bool seeked: false | ||
1714 | 215 | |||
1715 | 216 | onSeekingChanged: { | ||
1716 | 217 | if (seeking === false) { | ||
1717 | 218 | musicToolbarFullPositionLabel.text = durationToString(player.position) | ||
1718 | 219 | } | ||
1719 | 220 | } | ||
1720 | 221 | |||
1721 | 222 | onPressedChanged: { | ||
1722 | 223 | seeking = pressed | ||
1723 | 224 | |||
1724 | 225 | if (!pressed) { | ||
1725 | 226 | seeked = true | ||
1726 | 227 | player.seek(value) | ||
1727 | 228 | |||
1728 | 229 | musicToolbarFullPositionLabel.text = durationToString(value) | ||
1729 | 230 | } | ||
1730 | 231 | } | ||
1731 | 232 | |||
1732 | 233 | Connections { | ||
1733 | 234 | target: player | ||
1734 | 235 | onPositionChanged: { | ||
1735 | 236 | // seeked is a workaround for bug 1310706 as the first position after a seek is sometimes invalid (0) | ||
1736 | 237 | if (progressSliderMusic.seeking === false && !progressSliderMusic.seeked) { | ||
1737 | 238 | musicToolbarFullPositionLabel.text = durationToString(player.position) | ||
1738 | 239 | musicToolbarFullDurationLabel.text = durationToString(player.duration) | ||
1739 | 240 | |||
1740 | 241 | progressSliderMusic.value = player.position | ||
1741 | 242 | progressSliderMusic.maximumValue = player.duration | ||
1742 | 243 | } | ||
1743 | 244 | |||
1744 | 245 | progressSliderMusic.seeked = false; | ||
1745 | 246 | } | ||
1746 | 247 | onStopped: { | ||
1747 | 248 | musicToolbarFullPositionLabel.text = durationToString(0); | ||
1748 | 249 | musicToolbarFullDurationLabel.text = durationToString(0); | ||
1749 | 250 | } | ||
1750 | 251 | } | ||
1751 | 252 | } | ||
1752 | 253 | |||
1753 | 254 | /* Duration label */ | ||
1754 | 255 | Label { | ||
1755 | 256 | id: musicToolbarFullDurationLabel | ||
1756 | 257 | anchors.top: progressSliderMusic.bottom | ||
1757 | 258 | anchors.topMargin: units.gu(-2) | ||
1758 | 259 | anchors.right: parent.right | ||
1759 | 260 | color: styleMusic.nowPlaying.labelSecondaryColor | ||
1760 | 261 | fontSize: "small" | ||
1761 | 262 | height: parent.height | ||
1762 | 263 | horizontalAlignment: Text.AlignHCenter | ||
1763 | 264 | text: durationToString(player.duration) | ||
1764 | 265 | verticalAlignment: Text.AlignVCenter | ||
1765 | 266 | width: units.gu(3) | ||
1766 | 267 | } | ||
1767 | 268 | } | ||
1768 | 269 | } | ||
1769 | 270 | |||
1770 | 271 | Loader { | ||
1771 | 272 | id: queueListLoader | ||
1772 | 273 | anchors { | ||
1773 | 274 | fill: parent | ||
1774 | 275 | } | ||
1775 | 276 | asynchronous: true | ||
1776 | 277 | sourceComponent: MultiSelectListView { | ||
1777 | 278 | id: queueList | ||
1778 | 279 | anchors { | ||
1779 | 280 | bottomMargin: musicToolbarFullContainer.height + units.gu(2) | ||
1780 | 281 | fill: parent | ||
1781 | 282 | topMargin: units.gu(2) | ||
1782 | 283 | } | ||
1783 | 284 | delegate: queueDelegate | ||
1784 | 285 | footer: Item { | ||
1785 | 286 | height: mainView.height - (styleMusic.common.expandHeight + queueList.currentHeight) + units.gu(8) | ||
1786 | 287 | } | ||
1787 | 288 | model: trackQueue.model | ||
1788 | 289 | objectName: "nowPlayingqueueList" | ||
1789 | 290 | |||
1790 | 291 | property int normalHeight: units.gu(6) | ||
1791 | 292 | property int transitionDuration: 250 // transition length of animations | ||
1792 | 293 | |||
1793 | 294 | onCountChanged: customdebug("Queue: Now has: " + queueList.count + " tracks") | ||
1794 | 295 | |||
1795 | 296 | Component { | ||
1796 | 297 | id: queueDelegate | ||
1797 | 298 | ListItemWithActions { | ||
1798 | 299 | id: queueListItem | ||
1799 | 300 | color: player.currentIndex === index ? "#2c2c34" : styleMusic.mainView.backgroundColor | ||
1800 | 301 | height: queueList.normalHeight | ||
1801 | 302 | objectName: "nowPlayingListItem" + index | ||
1802 | 303 | state: "" | ||
1803 | 304 | |||
1804 | 305 | leftSideAction: Remove { | ||
1805 | 306 | onTriggered: trackQueue.removeQueueList([index]) | ||
1806 | 307 | } | ||
1807 | 308 | multiselectable: true | ||
1808 | 309 | reorderable: true | ||
1809 | 310 | rightSideActions: [ | ||
1810 | 311 | AddToPlaylist{ | ||
1811 | 312 | |||
1812 | 313 | } | ||
1813 | 314 | ] | ||
1814 | 315 | |||
1815 | 316 | onItemClicked: { | ||
1816 | 317 | customdebug("File: " + model.filename) // debugger | ||
1817 | 318 | trackQueueClick(index); // toggle track state | ||
1818 | 319 | } | ||
1819 | 320 | onReorder: { | ||
1820 | 321 | console.debug("Move: ", from, to); | ||
1821 | 322 | |||
1822 | 323 | trackQueue.model.move(from, to, 1); | ||
1823 | 324 | Library.moveQueueItem(from, to); | ||
1824 | 325 | |||
1825 | 326 | // Maintain currentIndex with current song | ||
1826 | 327 | if (from === player.currentIndex) { | ||
1827 | 328 | player.currentIndex = to; | ||
1828 | 329 | } | ||
1829 | 330 | else if (from < player.currentIndex && to >= player.currentIndex) { | ||
1830 | 331 | player.currentIndex -= 1; | ||
1831 | 332 | } | ||
1832 | 333 | else if (from > player.currentIndex && to <= player.currentIndex) { | ||
1833 | 334 | player.currentIndex += 1; | ||
1834 | 335 | } | ||
1835 | 336 | |||
1836 | 337 | queueIndex = player.currentIndex | ||
1837 | 338 | } | ||
1838 | 339 | |||
1839 | 340 | Item { | ||
1840 | 341 | id: trackContainer; | ||
1841 | 342 | anchors { | ||
1842 | 343 | fill: parent | ||
1843 | 344 | } | ||
1844 | 345 | |||
1845 | 346 | NumberAnimation { | ||
1846 | 347 | id: trackContainerReorderAnimation | ||
1847 | 348 | target: trackContainer; | ||
1848 | 349 | property: "anchors.leftMargin"; | ||
1849 | 350 | duration: queueList.transitionDuration; | ||
1850 | 351 | to: units.gu(2) | ||
1851 | 352 | } | ||
1852 | 353 | |||
1853 | 354 | NumberAnimation { | ||
1854 | 355 | id: trackContainerResetAnimation | ||
1855 | 356 | target: trackContainer; | ||
1856 | 357 | property: "anchors.leftMargin"; | ||
1857 | 358 | duration: queueList.transitionDuration; | ||
1858 | 359 | to: units.gu(0.5) | ||
1859 | 360 | } | ||
1860 | 361 | |||
1861 | 362 | MusicRow { | ||
1862 | 363 | id: musicRow | ||
1863 | 364 | height: parent.height | ||
1864 | 365 | column: Column { | ||
1865 | 366 | Label { | ||
1866 | 367 | id: trackTitle | ||
1867 | 368 | color: player.currentIndex === index ? UbuntuColors.blue | ||
1868 | 369 | : styleMusic.common.music | ||
1869 | 370 | fontSize: "small" | ||
1870 | 371 | objectName: "titleLabel" | ||
1871 | 372 | text: model.title | ||
1872 | 373 | } | ||
1873 | 374 | |||
1874 | 375 | Label { | ||
1875 | 376 | id: trackArtist | ||
1876 | 377 | color: styleMusic.common.subtitle | ||
1877 | 378 | fontSize: "x-small" | ||
1878 | 379 | objectName: "artistLabel" | ||
1879 | 380 | text: model.author | ||
1880 | 381 | } | ||
1881 | 382 | } | ||
1882 | 383 | } | ||
1883 | 384 | } | ||
1884 | 385 | } | ||
1885 | 386 | } | ||
1886 | 387 | } | ||
1887 | 388 | visible: isListView || wideAspect | ||
1888 | 389 | } | ||
1889 | 390 | |||
1890 | 391 | /* Full toolbar */ | ||
1891 | 392 | Rectangle { | ||
1892 | 393 | id: musicToolbarFullContainer | ||
1893 | 394 | anchors.bottom: parent.bottom | ||
1894 | 395 | color: styleMusic.common.black | ||
1895 | 396 | height: units.gu(10) | ||
1896 | 397 | width: parent.width | ||
1897 | 398 | |||
1898 | 399 | /* Repeat button */ | ||
1899 | 400 | MouseArea { | ||
1900 | 401 | id: nowPlayingRepeatButton | ||
1901 | 402 | anchors.right: nowPlayingPreviousButton.left | ||
1902 | 403 | anchors.rightMargin: units.gu(1) | ||
1903 | 404 | anchors.verticalCenter: nowPlayingPlayButton.verticalCenter | ||
1904 | 405 | height: units.gu(6) | ||
1905 | 406 | opacity: player.repeat && !emptyPageLoader.noMusic ? 1 : .4 | ||
1906 | 407 | width: height | ||
1907 | 408 | onClicked: player.repeat = !player.repeat | ||
1908 | 409 | |||
1909 | 410 | Icon { | ||
1910 | 411 | id: repeatIcon | ||
1911 | 412 | height: units.gu(3) | ||
1912 | 413 | width: height | ||
1913 | 414 | anchors.verticalCenter: parent.verticalCenter | ||
1914 | 415 | anchors.horizontalCenter: parent.horizontalCenter | ||
1915 | 416 | color: "white" | ||
1916 | 417 | name: "media-playlist-repeat" | ||
1917 | 418 | objectName: "repeatShape" | ||
1918 | 419 | opacity: player.repeat && !emptyPageLoader.noMusic ? 1 : .4 | ||
1919 | 420 | } | ||
1920 | 421 | } | ||
1921 | 422 | |||
1922 | 423 | /* Previous button */ | ||
1923 | 424 | MouseArea { | ||
1924 | 425 | id: nowPlayingPreviousButton | ||
1925 | 426 | anchors.right: nowPlayingPlayButton.left | ||
1926 | 427 | anchors.rightMargin: units.gu(1) | ||
1927 | 428 | anchors.verticalCenter: nowPlayingPlayButton.verticalCenter | ||
1928 | 429 | height: units.gu(6) | ||
1929 | 430 | opacity: trackQueue.model.count === 0 ? .4 : 1 | ||
1930 | 431 | width: height | ||
1931 | 432 | onClicked: player.previousSong() | ||
1932 | 433 | |||
1933 | 434 | Icon { | ||
1934 | 435 | id: nowPlayingPreviousIndicator | ||
1935 | 436 | height: units.gu(3) | ||
1936 | 437 | width: height | ||
1937 | 438 | anchors.verticalCenter: parent.verticalCenter | ||
1938 | 439 | anchors.horizontalCenter: parent.horizontalCenter | ||
1939 | 440 | color: "white" | ||
1940 | 441 | name: "media-skip-backward" | ||
1941 | 442 | objectName: "previousShape" | ||
1942 | 443 | opacity: 1 | ||
1943 | 444 | } | ||
1944 | 445 | } | ||
1945 | 446 | |||
1946 | 447 | /* Play/Pause button */ | ||
1947 | 448 | MouseArea { | ||
1948 | 449 | id: nowPlayingPlayButton | ||
1949 | 450 | anchors.centerIn: parent | ||
1950 | 451 | height: units.gu(10) | ||
1951 | 452 | width: height | ||
1952 | 453 | onClicked: player.toggle() | ||
1953 | 454 | |||
1954 | 455 | Icon { | ||
1955 | 456 | id: nowPlayingPlayIndicator | ||
1956 | 457 | height: units.gu(6) | ||
1957 | 458 | width: height | ||
1958 | 459 | anchors.verticalCenter: parent.verticalCenter | ||
1959 | 460 | anchors.horizontalCenter: parent.horizontalCenter | ||
1960 | 461 | opacity: emptyPageLoader.noMusic ? .4 : 1 | ||
1961 | 462 | color: "white" | ||
1962 | 463 | name: player.playbackState === MediaPlayer.PlayingState ? "media-playback-pause" : "media-playback-start" | ||
1963 | 464 | objectName: "playShape" | ||
1964 | 465 | } | ||
1965 | 466 | } | ||
1966 | 467 | |||
1967 | 468 | /* Next button */ | ||
1968 | 469 | MouseArea { | ||
1969 | 470 | id: nowPlayingNextButton | ||
1970 | 471 | anchors.left: nowPlayingPlayButton.right | ||
1971 | 472 | anchors.leftMargin: units.gu(1) | ||
1972 | 473 | anchors.verticalCenter: nowPlayingPlayButton.verticalCenter | ||
1973 | 474 | height: units.gu(6) | ||
1974 | 475 | opacity: trackQueue.model.count === 0 ? .4 : 1 | ||
1975 | 476 | width: height | ||
1976 | 477 | onClicked: player.nextSong() | ||
1977 | 478 | |||
1978 | 479 | Icon { | ||
1979 | 480 | id: nowPlayingNextIndicator | ||
1980 | 481 | height: units.gu(3) | ||
1981 | 482 | width: height | ||
1982 | 483 | anchors.verticalCenter: parent.verticalCenter | ||
1983 | 484 | anchors.horizontalCenter: parent.horizontalCenter | ||
1984 | 485 | color: "white" | ||
1985 | 486 | name: "media-skip-forward" | ||
1986 | 487 | objectName: "forwardShape" | ||
1987 | 488 | opacity: 1 | ||
1988 | 489 | } | ||
1989 | 490 | } | ||
1990 | 491 | |||
1991 | 492 | /* Shuffle button */ | ||
1992 | 493 | MouseArea { | ||
1993 | 494 | id: nowPlayingShuffleButton | ||
1994 | 495 | anchors.left: nowPlayingNextButton.right | ||
1995 | 496 | anchors.leftMargin: units.gu(1) | ||
1996 | 497 | anchors.verticalCenter: nowPlayingPlayButton.verticalCenter | ||
1997 | 498 | height: units.gu(6) | ||
1998 | 499 | opacity: player.shuffle && !emptyPageLoader.noMusic ? 1 : .4 | ||
1999 | 500 | width: height | ||
2000 | 501 | onClicked: player.shuffle = !player.shuffle | ||
2001 | 502 | |||
2002 | 503 | Icon { | ||
2003 | 504 | id: shuffleIcon | ||
2004 | 505 | height: units.gu(3) | ||
2005 | 506 | width: height | ||
2006 | 507 | anchors.verticalCenter: parent.verticalCenter | ||
2007 | 508 | anchors.horizontalCenter: parent.horizontalCenter | ||
2008 | 509 | color: "white" | ||
2009 | 510 | name: "media-playlist-shuffle" | ||
2010 | 511 | objectName: "shuffleShape" | ||
2011 | 512 | opacity: player.shuffle && !emptyPageLoader.noMusic ? 1 : .4 | ||
2012 | 513 | } | ||
2013 | 514 | } | ||
2014 | 515 | |||
2015 | 516 | /* Object which provides the progress bar when in the queue */ | ||
2016 | 517 | Rectangle { | ||
2017 | 518 | id: playerControlsProgressBar | ||
2018 | 519 | anchors { | ||
2019 | 520 | bottom: parent.bottom | ||
2020 | 521 | left: parent.left | ||
2021 | 522 | right: parent.right | ||
2022 | 523 | } | ||
2023 | 524 | color: styleMusic.common.black | ||
2024 | 525 | height: units.gu(0.25) | ||
2025 | 526 | visible: isListView || wideAspect | ||
2026 | 527 | |||
2027 | 528 | Rectangle { | ||
2028 | 529 | id: playerControlsProgressBarHint | ||
2029 | 530 | anchors { | ||
2030 | 531 | left: parent.left | ||
2031 | 532 | bottom: parent.bottom | ||
2032 | 533 | } | ||
2033 | 534 | color: UbuntuColors.blue | ||
2034 | 535 | height: parent.height | ||
2035 | 536 | width: player.duration > 0 ? (player.position / player.duration) * playerControlsProgressBar.width : 0 | ||
2036 | 537 | |||
2037 | 538 | Connections { | ||
2038 | 539 | target: player | ||
2039 | 540 | onPositionChanged: { | ||
2040 | 541 | playerControlsProgressBarHint.width = (player.position / player.duration) * playerControlsProgressBar.width | ||
2041 | 542 | } | ||
2042 | 543 | onStopped: { | ||
2043 | 544 | playerControlsProgressBarHint.width = 0; | ||
2044 | 545 | } | ||
2045 | 546 | } | ||
2046 | 547 | } | ||
2047 | 548 | } | ||
2048 | 549 | } | ||
2049 | 550 | } | ||
2050 | 0 | 551 | ||
2051 | === renamed file 'Player.qml' => 'app/components/Player.qml' | |||
2052 | === added file 'app/components/PlaylistsEmptyState.qml' | |||
2053 | --- app/components/PlaylistsEmptyState.qml 1970-01-01 00:00:00 +0000 | |||
2054 | +++ app/components/PlaylistsEmptyState.qml 2015-02-10 03:13:44 +0000 | |||
2055 | @@ -0,0 +1,58 @@ | |||
2056 | 1 | /* | ||
2057 | 2 | * Copyright (C) 2013, 2014, 2015 | ||
2058 | 3 | * Andrew Hayzen <ahayzen@gmail.com> | ||
2059 | 4 | * Daniel Holm <d.holmen@gmail.com> | ||
2060 | 5 | * Victor Thompson <victor.thompson@gmail.com> | ||
2061 | 6 | * | ||
2062 | 7 | * This program is free software; you can redistribute it and/or modify | ||
2063 | 8 | * it under the terms of the GNU General Public License as published by | ||
2064 | 9 | * the Free Software Foundation; version 3. | ||
2065 | 10 | * | ||
2066 | 11 | * This program is distributed in the hope that it will be useful, | ||
2067 | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
2068 | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
2069 | 14 | * GNU General Public License for more details. | ||
2070 | 15 | * | ||
2071 | 16 | * You should have received a copy of the GNU General Public License | ||
2072 | 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
2073 | 18 | */ | ||
2074 | 19 | |||
2075 | 20 | import QtQuick 2.3 | ||
2076 | 21 | import Ubuntu.Components 1.1 | ||
2077 | 22 | |||
2078 | 23 | |||
2079 | 24 | Rectangle { | ||
2080 | 25 | id: playlistsEmptyState | ||
2081 | 26 | anchors { | ||
2082 | 27 | fill: parent | ||
2083 | 28 | } | ||
2084 | 29 | color: mainView.backgroundColor | ||
2085 | 30 | |||
2086 | 31 | Column { | ||
2087 | 32 | anchors.centerIn: parent | ||
2088 | 33 | spacing: units.gu(4) | ||
2089 | 34 | width: units.gu(36) | ||
2090 | 35 | |||
2091 | 36 | Label { | ||
2092 | 37 | color: styleMusic.libraryEmpty.labelColor | ||
2093 | 38 | elide: Text.ElideRight | ||
2094 | 39 | fontSize: "x-large" | ||
2095 | 40 | horizontalAlignment: Text.AlignLeft | ||
2096 | 41 | maximumLineCount: 2 | ||
2097 | 42 | text: i18n.tr("No playlists found") | ||
2098 | 43 | width: parent.width | ||
2099 | 44 | wrapMode: Text.WordWrap | ||
2100 | 45 | } | ||
2101 | 46 | |||
2102 | 47 | Label { | ||
2103 | 48 | color: styleMusic.libraryEmpty.labelColor | ||
2104 | 49 | elide: Text.ElideRight | ||
2105 | 50 | fontSize: "large" | ||
2106 | 51 | horizontalAlignment: Text.AlignLeft | ||
2107 | 52 | maximumLineCount: 4 | ||
2108 | 53 | text: i18n.tr("Get more out of Music by tapping the %1 icon to start making playlists for every mood and occasion.").arg('"+"') | ||
2109 | 54 | width: parent.width | ||
2110 | 55 | wrapMode: Text.WordWrap | ||
2111 | 56 | } | ||
2112 | 57 | } | ||
2113 | 58 | } | ||
2114 | 0 | 59 | ||
2115 | === renamed file 'Style.qml' => 'app/components/Style.qml' | |||
2116 | === added directory 'app/components/ViewButton' | |||
2117 | === added file 'app/components/ViewButton/CMakeLists.txt' | |||
2118 | --- app/components/ViewButton/CMakeLists.txt 1970-01-01 00:00:00 +0000 | |||
2119 | +++ app/components/ViewButton/CMakeLists.txt 2015-02-10 03:13:44 +0000 | |||
2120 | @@ -0,0 +1,4 @@ | |||
2121 | 1 | # make the qml files visible on qtcreator | ||
2122 | 2 | file(GLOB VIEW_BUTTON_QML_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.qml) | ||
2123 | 3 | |||
2124 | 4 | add_custom_target(com_ubuntu_music_VIEW_BUTTON_QMLFiles ALL SOURCES ${VIEW_BUTTON_QML_FILES}) | ||
2125 | 0 | 5 | ||
2126 | === added file 'app/components/ViewButton/PlayAllButton.qml' | |||
2127 | --- app/components/ViewButton/PlayAllButton.qml 1970-01-01 00:00:00 +0000 | |||
2128 | +++ app/components/ViewButton/PlayAllButton.qml 2015-02-10 03:13:44 +0000 | |||
2129 | @@ -0,0 +1,34 @@ | |||
2130 | 1 | /* | ||
2131 | 2 | * Copyright (C) 2013, 2014, 2015 | ||
2132 | 3 | * Andrew Hayzen <ahayzen@gmail.com> | ||
2133 | 4 | * Daniel Holm <d.holmen@gmail.com> | ||
2134 | 5 | * Victor Thompson <victor.thompson@gmail.com> | ||
2135 | 6 | * | ||
2136 | 7 | * This program is free software; you can redistribute it and/or modify | ||
2137 | 8 | * it under the terms of the GNU General Public License as published by | ||
2138 | 9 | * the Free Software Foundation; version 3. | ||
2139 | 10 | * | ||
2140 | 11 | * This program is distributed in the hope that it will be useful, | ||
2141 | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
2142 | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
2143 | 14 | * GNU General Public License for more details. | ||
2144 | 15 | * | ||
2145 | 16 | * You should have received a copy of the GNU General Public License | ||
2146 | 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
2147 | 18 | */ | ||
2148 | 19 | |||
2149 | 20 | import QtQuick 2.3 | ||
2150 | 21 | import Ubuntu.Components 1.1 | ||
2151 | 22 | |||
2152 | 23 | |||
2153 | 24 | Button { | ||
2154 | 25 | color: UbuntuColors.green | ||
2155 | 26 | height: units.gu(4) | ||
2156 | 27 | // TRANSLATORS: this appears in a button with limited space (around 14 characters) | ||
2157 | 28 | text: i18n.tr("Play all") | ||
2158 | 29 | width: units.gu(15) | ||
2159 | 30 | |||
2160 | 31 | property var model | ||
2161 | 32 | |||
2162 | 33 | onClicked: trackClicked(model, 0) // play track | ||
2163 | 34 | } | ||
2164 | 0 | 35 | ||
2165 | === added file 'app/components/ViewButton/QueueAllButton.qml' | |||
2166 | --- app/components/ViewButton/QueueAllButton.qml 1970-01-01 00:00:00 +0000 | |||
2167 | +++ app/components/ViewButton/QueueAllButton.qml 2015-02-10 03:13:44 +0000 | |||
2168 | @@ -0,0 +1,46 @@ | |||
2169 | 1 | /* | ||
2170 | 2 | * Copyright (C) 2013, 2014, 2015 | ||
2171 | 3 | * Andrew Hayzen <ahayzen@gmail.com> | ||
2172 | 4 | * Daniel Holm <d.holmen@gmail.com> | ||
2173 | 5 | * Victor Thompson <victor.thompson@gmail.com> | ||
2174 | 6 | * | ||
2175 | 7 | * This program is free software; you can redistribute it and/or modify | ||
2176 | 8 | * it under the terms of the GNU General Public License as published by | ||
2177 | 9 | * the Free Software Foundation; version 3. | ||
2178 | 10 | * | ||
2179 | 11 | * This program is distributed in the hope that it will be useful, | ||
2180 | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
2181 | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
2182 | 14 | * GNU General Public License for more details. | ||
2183 | 15 | * | ||
2184 | 16 | * You should have received a copy of the GNU General Public License | ||
2185 | 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
2186 | 18 | */ | ||
2187 | 19 | |||
2188 | 20 | import QtQuick 2.3 | ||
2189 | 21 | import Ubuntu.Components 1.1 | ||
2190 | 22 | |||
2191 | 23 | |||
2192 | 24 | Button { | ||
2193 | 25 | height: units.gu(4) | ||
2194 | 26 | strokeColor: UbuntuColors.green | ||
2195 | 27 | width: units.gu(15) | ||
2196 | 28 | |||
2197 | 29 | property var model | ||
2198 | 30 | |||
2199 | 31 | onClicked: addQueueFromModel(model) | ||
2200 | 32 | |||
2201 | 33 | Text { | ||
2202 | 34 | anchors { | ||
2203 | 35 | centerIn: parent | ||
2204 | 36 | } | ||
2205 | 37 | color: "white" | ||
2206 | 38 | elide: Text.ElideRight | ||
2207 | 39 | height: parent.height | ||
2208 | 40 | horizontalAlignment: Text.AlignHCenter | ||
2209 | 41 | // TRANSLATORS: this appears in a button with limited space (around 14 characters) | ||
2210 | 42 | text: i18n.tr("Queue all") | ||
2211 | 43 | verticalAlignment: Text.AlignVCenter | ||
2212 | 44 | width: parent.width - units.gu(2) | ||
2213 | 45 | } | ||
2214 | 46 | } | ||
2215 | 0 | 47 | ||
2216 | === added file 'app/components/ViewButton/ShuffleButton.qml' | |||
2217 | --- app/components/ViewButton/ShuffleButton.qml 1970-01-01 00:00:00 +0000 | |||
2218 | +++ app/components/ViewButton/ShuffleButton.qml 2015-02-10 03:13:44 +0000 | |||
2219 | @@ -0,0 +1,46 @@ | |||
2220 | 1 | /* | ||
2221 | 2 | * Copyright (C) 2013, 2014, 2015 | ||
2222 | 3 | * Andrew Hayzen <ahayzen@gmail.com> | ||
2223 | 4 | * Daniel Holm <d.holmen@gmail.com> | ||
2224 | 5 | * Victor Thompson <victor.thompson@gmail.com> | ||
2225 | 6 | * | ||
2226 | 7 | * This program is free software; you can redistribute it and/or modify | ||
2227 | 8 | * it under the terms of the GNU General Public License as published by | ||
2228 | 9 | * the Free Software Foundation; version 3. | ||
2229 | 10 | * | ||
2230 | 11 | * This program is distributed in the hope that it will be useful, | ||
2231 | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
2232 | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
2233 | 14 | * GNU General Public License for more details. | ||
2234 | 15 | * | ||
2235 | 16 | * You should have received a copy of the GNU General Public License | ||
2236 | 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
2237 | 18 | */ | ||
2238 | 19 | |||
2239 | 20 | import QtQuick 2.3 | ||
2240 | 21 | import Ubuntu.Components 1.1 | ||
2241 | 22 | |||
2242 | 23 | |||
2243 | 24 | Button { | ||
2244 | 25 | height: units.gu(4) | ||
2245 | 26 | strokeColor: UbuntuColors.green | ||
2246 | 27 | width: units.gu(15) | ||
2247 | 28 | |||
2248 | 29 | property var model | ||
2249 | 30 | |||
2250 | 31 | onClicked: shuffleModel(model) | ||
2251 | 32 | |||
2252 | 33 | Text { | ||
2253 | 34 | anchors { | ||
2254 | 35 | centerIn: parent | ||
2255 | 36 | } | ||
2256 | 37 | color: "white" | ||
2257 | 38 | elide: Text.ElideRight | ||
2258 | 39 | height: parent.height | ||
2259 | 40 | horizontalAlignment: Text.AlignHCenter | ||
2260 | 41 | // TRANSLATORS: this appears in a button with limited space (around 14 characters) | ||
2261 | 42 | text: i18n.tr("Shuffle") | ||
2262 | 43 | verticalAlignment: Text.AlignVCenter | ||
2263 | 44 | width: parent.width - units.gu(2) | ||
2264 | 45 | } | ||
2265 | 46 | } | ||
2266 | 0 | 47 | ||
2267 | === modified file 'app/components/Walkthrough/Slide1.qml' | |||
2268 | --- common/Walkthrough/Slide1.qml 2015-02-02 14:03:12 +0000 | |||
2269 | +++ app/components/Walkthrough/Slide1.qml 2015-02-10 03:13:44 +0000 | |||
2270 | @@ -39,7 +39,7 @@ | |||
2271 | 39 | height: (parent.height - bodyText.contentHeight - introductionText.height - 4*units.gu(4))/2 | 39 | height: (parent.height - bodyText.contentHeight - introductionText.height - 4*units.gu(4))/2 |
2272 | 40 | image: Image { | 40 | image: Image { |
2273 | 41 | id: centerImage | 41 | id: centerImage |
2275 | 42 | source: Qt.resolvedUrl("../../images/music-app@30.png") | 42 | source: Qt.resolvedUrl("../../graphics/music-app@30.png") |
2276 | 43 | } | 43 | } |
2277 | 44 | radius: "medium" | 44 | radius: "medium" |
2278 | 45 | width: height | 45 | width: height |
2279 | 46 | 46 | ||
2280 | === modified file 'app/components/Walkthrough/Slide2.qml' | |||
2281 | --- common/Walkthrough/Slide2.qml 2015-02-02 13:37:23 +0000 | |||
2282 | +++ app/components/Walkthrough/Slide2.qml 2015-02-10 03:13:44 +0000 | |||
2283 | @@ -38,7 +38,7 @@ | |||
2284 | 38 | } | 38 | } |
2285 | 39 | height: (parent.height - bodyText.contentHeight - introductionText.height - 4*units.gu(4))/2 | 39 | height: (parent.height - bodyText.contentHeight - introductionText.height - 4*units.gu(4))/2 |
2286 | 40 | fillMode: Image.PreserveAspectFit | 40 | fillMode: Image.PreserveAspectFit |
2288 | 41 | source: Qt.resolvedUrl("../../images/sd_phone_icon.png") | 41 | source: Qt.resolvedUrl("../../graphics/sd_phone_icon.png") |
2289 | 42 | } | 42 | } |
2290 | 43 | 43 | ||
2291 | 44 | Label { | 44 | Label { |
2292 | 45 | 45 | ||
2293 | === modified file 'app/components/Walkthrough/Slide3.qml' | |||
2294 | --- common/Walkthrough/Slide3.qml 2015-02-02 13:37:23 +0000 | |||
2295 | +++ app/components/Walkthrough/Slide3.qml 2015-02-10 03:13:44 +0000 | |||
2296 | @@ -38,7 +38,7 @@ | |||
2297 | 38 | } | 38 | } |
2298 | 39 | height: (parent.height - introductionText.height - finalMessage.contentHeight - 4.5*units.gu(4))/2 | 39 | height: (parent.height - introductionText.height - finalMessage.contentHeight - 4.5*units.gu(4))/2 |
2299 | 40 | fillMode: Image.PreserveAspectFit | 40 | fillMode: Image.PreserveAspectFit |
2301 | 41 | source: Qt.resolvedUrl("../../images/music_download_icon.png") | 41 | source: Qt.resolvedUrl("../../graphics/music_download_icon.png") |
2302 | 42 | } | 42 | } |
2303 | 43 | 43 | ||
2304 | 44 | Label { | 44 | Label { |
2305 | 45 | 45 | ||
2306 | === modified file 'app/components/Walkthrough/Walkthrough.qml' | |||
2307 | --- common/Walkthrough/Walkthrough.qml 2015-01-31 02:47:16 +0000 | |||
2308 | +++ app/components/Walkthrough/Walkthrough.qml 2015-02-10 03:13:44 +0000 | |||
2309 | @@ -134,7 +134,7 @@ | |||
2310 | 134 | anchors.verticalCenter: parent.verticalCenter | 134 | anchors.verticalCenter: parent.verticalCenter |
2311 | 135 | antialiasing: true | 135 | antialiasing: true |
2312 | 136 | height: width | 136 | height: width |
2314 | 137 | source: listView.currentIndex == index ? "../../images/Ellipse@27.png" : "../../images/Ellipse_15_opacity@27.png" | 137 | source: listView.currentIndex == index ? "../../graphics/Ellipse@27.png" : "../../graphics/Ellipse_15_opacity@27.png" |
2315 | 138 | width: units.gu(1.5) | 138 | width: units.gu(1.5) |
2316 | 139 | } | 139 | } |
2317 | 140 | } | 140 | } |
2318 | 141 | 141 | ||
2319 | === renamed file 'WorkerModelLoader.qml' => 'app/components/WorkerModelLoader.qml' | |||
2320 | --- WorkerModelLoader.qml 2015-02-01 03:35:07 +0000 | |||
2321 | +++ app/components/WorkerModelLoader.qml 2015-02-10 03:13:44 +0000 | |||
2322 | @@ -21,7 +21,7 @@ | |||
2323 | 21 | 21 | ||
2324 | 22 | WorkerScript { | 22 | WorkerScript { |
2325 | 23 | id: worker | 23 | id: worker |
2327 | 24 | source: "worker-library-loader.js" | 24 | source: "../logic/worker-library-loader.js" |
2328 | 25 | 25 | ||
2329 | 26 | property bool canLoad: true | 26 | property bool canLoad: true |
2330 | 27 | property bool completed: false | 27 | property bool completed: false |
2331 | 28 | 28 | ||
2332 | === renamed directory 'images' => 'app/graphics' | |||
2333 | === added directory 'app/logic' | |||
2334 | === added file 'app/logic/CMakeLists.txt' | |||
2335 | --- app/logic/CMakeLists.txt 1970-01-01 00:00:00 +0000 | |||
2336 | +++ app/logic/CMakeLists.txt 2015-02-10 03:13:44 +0000 | |||
2337 | @@ -0,0 +1,4 @@ | |||
2338 | 1 | # make the qml files visible on qtcreator | ||
2339 | 2 | file(GLOB LOGIC_JS_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.js) | ||
2340 | 3 | |||
2341 | 4 | add_custom_target(com_ubuntu_music_LOGIC_JSFiles ALL SOURCES ${LOGIC_JS_FILES}) | ||
2342 | 0 | 5 | ||
2343 | === renamed file 'meta-database.js' => 'app/logic/meta-database.js' | |||
2344 | === renamed file 'playlists.js' => 'app/logic/playlists.js' | |||
2345 | === renamed file 'worker-library-loader.js' => 'app/logic/worker-library-loader.js' | |||
2346 | === renamed file 'music-app.qml' => 'app/music-app.qml' | |||
2347 | --- music-app.qml 2015-02-05 22:40:14 +0000 | |||
2348 | +++ app/music-app.qml 2015-02-10 03:13:44 +0000 | |||
2349 | @@ -22,15 +22,17 @@ | |||
2350 | 22 | import Ubuntu.Components.Popups 1.0 | 22 | import Ubuntu.Components.Popups 1.0 |
2351 | 23 | import Ubuntu.Components.ListItems 1.0 as ListItem | 23 | import Ubuntu.Components.ListItems 1.0 as ListItem |
2352 | 24 | import Ubuntu.Content 0.1 | 24 | import Ubuntu.Content 0.1 |
2353 | 25 | import Ubuntu.Layouts 1.0 | ||
2354 | 25 | import Ubuntu.MediaScanner 0.1 | 26 | import Ubuntu.MediaScanner 0.1 |
2355 | 26 | import Qt.labs.settings 1.0 | 27 | import Qt.labs.settings 1.0 |
2356 | 27 | import QtMultimedia 5.0 | 28 | import QtMultimedia 5.0 |
2357 | 28 | import QtQuick.LocalStorage 2.0 | 29 | import QtQuick.LocalStorage 2.0 |
2358 | 29 | import QtGraphicalEffects 1.0 | 30 | import QtGraphicalEffects 1.0 |
2359 | 30 | import UserMetrics 0.1 | 31 | import UserMetrics 0.1 |
2363 | 31 | import "meta-database.js" as Library | 32 | import "logic/meta-database.js" as Library |
2364 | 32 | import "playlists.js" as Playlists | 33 | import "logic/playlists.js" as Playlists |
2365 | 33 | import "common" | 34 | import "components" |
2366 | 35 | import "ui" | ||
2367 | 34 | 36 | ||
2368 | 35 | MainView { | 37 | MainView { |
2369 | 36 | objectName: "music" | 38 | objectName: "music" |
2370 | @@ -55,10 +57,10 @@ | |||
2371 | 55 | focus: true | 57 | focus: true |
2372 | 56 | Keys.onPressed: { | 58 | Keys.onPressed: { |
2373 | 57 | if(event.key === Qt.Key_Escape) { | 59 | if(event.key === Qt.Key_Escape) { |
2376 | 58 | if (musicToolbar.currentPage.searchable && musicToolbar.currentPage.state === "search") { | 60 | if (mainPageStack.currentMusicPage.searchable && mainPageStack.currentMusicPage.state === "search") { |
2377 | 59 | musicToolbar.currentPage.state = "default" | 61 | mainPageStack.currentMusicPage.state = "default" |
2378 | 60 | } else { | 62 | } else { |
2380 | 61 | musicToolbar.goBack(); // Esc Go back | 63 | mainPageStack.goBack(); // Esc Go back |
2381 | 62 | } | 64 | } |
2382 | 63 | } | 65 | } |
2383 | 64 | else if(event.modifiers === Qt.AltModifier) { | 66 | else if(event.modifiers === Qt.AltModifier) { |
2384 | @@ -95,8 +97,8 @@ | |||
2385 | 95 | player.repeat = !player.repeat | 97 | player.repeat = !player.repeat |
2386 | 96 | break; | 98 | break; |
2387 | 97 | case Qt.Key_F: // Ctrl+F Show Search popup | 99 | case Qt.Key_F: // Ctrl+F Show Search popup |
2390 | 98 | if (musicToolbar.currentPage.searchable && musicToolbar.currentPage.state === "default") { | 100 | if (mainPageStack.currentMusicPage.searchable && mainPageStack.currentMusicPage.state === "default") { |
2391 | 99 | musicToolbar.currentPage.state = "search" | 101 | mainPageStack.currentMusicPage.state = "search" |
2392 | 100 | header.show() | 102 | header.show() |
2393 | 101 | } | 103 | } |
2394 | 102 | 104 | ||
2395 | @@ -159,7 +161,7 @@ | |||
2396 | 159 | id: backAction | 161 | id: backAction |
2397 | 160 | text: i18n.tr("Back") | 162 | text: i18n.tr("Back") |
2398 | 161 | keywords: i18n.tr("Go back to last page") | 163 | keywords: i18n.tr("Go back to last page") |
2400 | 162 | onTriggered: musicToolbar.goBack(); | 164 | onTriggered: mainPageStack.goBack(); |
2401 | 163 | } | 165 | } |
2402 | 164 | 166 | ||
2403 | 165 | // With a default Quit action only the first 4 actions are displayed | 167 | // With a default Quit action only the first 4 actions are displayed |
2404 | @@ -304,7 +306,7 @@ | |||
2405 | 304 | 306 | ||
2406 | 305 | if (success === true) { | 307 | if (success === true) { |
2407 | 306 | if (contentHubWaitForFile.processId === -1) { | 308 | if (contentHubWaitForFile.processId === -1) { |
2409 | 307 | contentHubWaitForFile.dialog = PopupUtils.open(contentHubWait, mainView) | 309 | contentHubWaitForFile.dialog = PopupUtils.open(Qt.resolvedUrl("components/Dialog/ContentHubWaitDialog.qml"), mainView) |
2410 | 308 | contentHubWaitForFile.searchPaths = contentHub.searchPaths; | 310 | contentHubWaitForFile.searchPaths = contentHub.searchPaths; |
2411 | 309 | contentHubWaitForFile.processId = processId; | 311 | contentHubWaitForFile.processId = processId; |
2412 | 310 | contentHubWaitForFile.start(); | 312 | contentHubWaitForFile.start(); |
2413 | @@ -318,7 +320,7 @@ | |||
2414 | 318 | } | 320 | } |
2415 | 319 | } | 321 | } |
2416 | 320 | else { | 322 | else { |
2418 | 321 | var errordialog = PopupUtils.open(contentHubError, mainView) | 323 | var errordialog = PopupUtils.open(Qt.resolvedUrl("components/Dialog/ContentHubErrorDialog.qml"), mainView) |
2419 | 322 | errordialog.errorText = err.join("\n") | 324 | errordialog.errorText = err.join("\n") |
2420 | 323 | } | 325 | } |
2421 | 324 | } | 326 | } |
2422 | @@ -416,7 +418,7 @@ | |||
2423 | 416 | stopTimer(); | 418 | stopTimer(); |
2424 | 417 | 419 | ||
2425 | 418 | console.debug("File(s) were not found", JSON.stringify(searchPaths)) | 420 | console.debug("File(s) were not found", JSON.stringify(searchPaths)) |
2427 | 419 | PopupUtils.open(contentHubNotFound, mainView) | 421 | PopupUtils.open(Qt.resolvedUrl("components/Dialog/ContentHubNotFoundDialog.qml"), mainView) |
2428 | 420 | } | 422 | } |
2429 | 421 | } | 423 | } |
2430 | 422 | else { | 424 | else { |
2431 | @@ -435,67 +437,6 @@ | |||
2432 | 435 | } | 437 | } |
2433 | 436 | } | 438 | } |
2434 | 437 | 439 | ||
2435 | 438 | Component { | ||
2436 | 439 | id: contentHubWait | ||
2437 | 440 | Dialog { | ||
2438 | 441 | id: dialogContentHubWait | ||
2439 | 442 | |||
2440 | 443 | LoadingSpinnerComponent { | ||
2441 | 444 | anchors { | ||
2442 | 445 | margins: units.gu(0) | ||
2443 | 446 | } | ||
2444 | 447 | loadingText: i18n.tr("Waiting for file(s)...") | ||
2445 | 448 | visible: true | ||
2446 | 449 | } | ||
2447 | 450 | } | ||
2448 | 451 | } | ||
2449 | 452 | |||
2450 | 453 | Component { | ||
2451 | 454 | id: contentHubError | ||
2452 | 455 | Dialog { | ||
2453 | 456 | id: dialogContentHubError | ||
2454 | 457 | |||
2455 | 458 | property alias errorText: errorLabel.text | ||
2456 | 459 | |||
2457 | 460 | Label { | ||
2458 | 461 | id: errorLabel | ||
2459 | 462 | color: styleMusic.common.black | ||
2460 | 463 | } | ||
2461 | 464 | |||
2462 | 465 | Button { | ||
2463 | 466 | text: i18n.tr("OK") | ||
2464 | 467 | onClicked: PopupUtils.close(dialogContentHubError) | ||
2465 | 468 | } | ||
2466 | 469 | } | ||
2467 | 470 | } | ||
2468 | 471 | |||
2469 | 472 | Component { | ||
2470 | 473 | id: contentHubNotFound | ||
2471 | 474 | Dialog { | ||
2472 | 475 | id: dialogContentHubNotFound | ||
2473 | 476 | |||
2474 | 477 | Label { | ||
2475 | 478 | color: styleMusic.common.black | ||
2476 | 479 | text: i18n.tr("Imported file not found") | ||
2477 | 480 | } | ||
2478 | 481 | |||
2479 | 482 | Button { | ||
2480 | 483 | text: i18n.tr("Wait") | ||
2481 | 484 | onClicked: { | ||
2482 | 485 | PopupUtils.close(dialogContentHubNotFound) | ||
2483 | 486 | |||
2484 | 487 | contentHubWaitForFile.dialog = PopupUtils.open(contentHubWait, mainView) | ||
2485 | 488 | contentHubWaitForFile.start(); | ||
2486 | 489 | } | ||
2487 | 490 | } | ||
2488 | 491 | |||
2489 | 492 | Button { | ||
2490 | 493 | text: i18n.tr("Cancel") | ||
2491 | 494 | onClicked: PopupUtils.close(dialogContentHubNotFound) | ||
2492 | 495 | } | ||
2493 | 496 | } | ||
2494 | 497 | } | ||
2495 | 498 | |||
2496 | 499 | // UserMetrics to show Music stuff on welcome screen | 440 | // UserMetrics to show Music stuff on welcome screen |
2497 | 500 | Metric { | 441 | Metric { |
2498 | 501 | id: songsMetric | 442 | id: songsMetric |
2499 | @@ -607,9 +548,7 @@ | |||
2500 | 607 | 548 | ||
2501 | 608 | // Display walkthrough on first run, even if the user has music | 549 | // Display walkthrough on first run, even if the user has music |
2502 | 609 | if (firstRun) { | 550 | if (firstRun) { |
2506 | 610 | var comp = Qt.createComponent("common/Walkthrough/FirstRunWalkthrough.qml") | 551 | mainPageStack.push(Qt.resolvedUrl("components/Walkthrough/FirstRunWalkthrough.qml"), {}) |
2504 | 611 | var walkthrough = comp.createObject(mainPageStack, {}); | ||
2505 | 612 | mainPageStack.push(walkthrough) | ||
2507 | 613 | } | 552 | } |
2508 | 614 | 553 | ||
2509 | 615 | if (args.values.url) { | 554 | if (args.values.url) { |
2510 | @@ -808,10 +747,10 @@ | |||
2511 | 808 | 747 | ||
2512 | 809 | // TODO: improve in refactoring to be able detect when a track is removed | 748 | // TODO: improve in refactoring to be able detect when a track is removed |
2513 | 810 | // Update playlists page | 749 | // Update playlists page |
2515 | 811 | if (musicPlaylistPage.visible) { | 750 | if (playlistsPage.visible) { |
2516 | 812 | playlistModel.filterPlaylists() | 751 | playlistModel.filterPlaylists() |
2517 | 813 | } else { | 752 | } else { |
2519 | 814 | musicPlaylistPage.changed = true | 753 | playlistsPage.changed = true |
2520 | 815 | } | 754 | } |
2521 | 816 | } | 755 | } |
2522 | 817 | } | 756 | } |
2523 | @@ -847,10 +786,10 @@ | |||
2524 | 847 | console.debug("Removed recent:", JSON.stringify(removed)) | 786 | console.debug("Removed recent:", JSON.stringify(removed)) |
2525 | 848 | Library.recentRemoveAlbums(removed) | 787 | Library.recentRemoveAlbums(removed) |
2526 | 849 | 788 | ||
2528 | 850 | if (musicStartPage.visible) { | 789 | if (recentPage.visible) { |
2529 | 851 | recentModel.filterRecent() | 790 | recentModel.filterRecent() |
2530 | 852 | } else { | 791 | } else { |
2532 | 853 | musicStartPage.changed = true | 792 | recentPage.changed = true |
2533 | 854 | } | 793 | } |
2534 | 855 | } | 794 | } |
2535 | 856 | } | 795 | } |
2536 | @@ -965,7 +904,7 @@ | |||
2537 | 965 | if (trackQueue.model.count === 0) { | 904 | if (trackQueue.model.count === 0) { |
2538 | 966 | // Nothing in the queue so stop and pop the queue | 905 | // Nothing in the queue so stop and pop the queue |
2539 | 967 | player.stop() | 906 | player.stop() |
2541 | 968 | musicToolbar.goBack() | 907 | mainPageStack.goBack() |
2542 | 969 | } else if (items.indexOf(player.currentIndex) > -1) { | 908 | } else if (items.indexOf(player.currentIndex) > -1) { |
2543 | 970 | // Current track was removed | 909 | // Current track was removed |
2544 | 971 | 910 | ||
2545 | @@ -1022,6 +961,7 @@ | |||
2546 | 1022 | if (preLoadComplete) | 961 | if (preLoadComplete) |
2547 | 1023 | { | 962 | { |
2548 | 1024 | loading.visible = false | 963 | loading.visible = false |
2549 | 964 | <<<<<<< TREE | ||
2550 | 1025 | playlistTab.loading = false | 965 | playlistTab.loading = false |
2551 | 1026 | playlistTab.populated = true | 966 | playlistTab.populated = true |
2552 | 1027 | } | 967 | } |
2553 | @@ -1401,82 +1341,339 @@ | |||
2554 | 1401 | 1341 | ||
2555 | 1402 | Image { | 1342 | Image { |
2556 | 1403 | id: imageEmptySD | 1343 | id: imageEmptySD |
2557 | 1344 | ======= | ||
2558 | 1345 | playlistsTab.loading = false | ||
2559 | 1346 | playlistsTab.populated = true | ||
2560 | 1347 | } | ||
2561 | 1348 | } | ||
2562 | 1349 | } | ||
2563 | 1350 | |||
2564 | 1351 | Layouts { | ||
2565 | 1352 | objectName: "musicLayout" | ||
2566 | 1353 | id: layouts | ||
2567 | 1354 | anchors.fill: parent | ||
2568 | 1355 | layouts: [ | ||
2569 | 1356 | ConditionalLayout { | ||
2570 | 1357 | name: "wideAspect" | ||
2571 | 1358 | when: wideAspect | ||
2572 | 1359 | Rectangle { | ||
2573 | 1360 | anchors.fill: parent | ||
2574 | 1361 | color: "transparent" | ||
2575 | 1362 | Rectangle { | ||
2576 | 1363 | width: layouts.width*0.375 | ||
2577 | 1364 | >>>>>>> MERGE-SOURCE | ||
2578 | 1404 | anchors { | 1365 | anchors { |
2616 | 1405 | verticalCenter: parent.verticalCenter | 1366 | top: parent.top |
2617 | 1406 | } | 1367 | bottom:parent.bottom |
2618 | 1407 | antialiasing: true | 1368 | right: parent.right |
2619 | 1408 | fillMode: Image.PreserveAspectFit | 1369 | } |
2620 | 1409 | height: units.gu(7) | 1370 | color: "transparent" |
2621 | 1410 | smooth: true | 1371 | |
2622 | 1411 | source: "images/music_empty_SD.png" | 1372 | NowPlaying { |
2623 | 1412 | } | 1373 | id: nowPlaying |
2624 | 1413 | } | 1374 | Layouts.item: "nowPlaying" |
2625 | 1414 | 1375 | } | |
2626 | 1415 | Label { | 1376 | } |
2627 | 1416 | color: styleMusic.libraryEmpty.labelColor | 1377 | } |
2628 | 1417 | elide: Text.ElideRight | 1378 | } |
2629 | 1418 | fontSize: "x-large" | 1379 | ] |
2630 | 1419 | horizontalAlignment: Text.AlignLeft | 1380 | |
2631 | 1420 | maximumLineCount: 2 | 1381 | Loader { |
2632 | 1421 | text: i18n.tr("No music found") | 1382 | id: musicToolbar |
2633 | 1422 | width: parent.width | 1383 | anchors { |
2634 | 1423 | wrapMode: Text.WordWrap | 1384 | bottom: parent.bottom |
2635 | 1424 | } | 1385 | left: parent.left |
2636 | 1425 | 1386 | right: parent.right | |
2637 | 1426 | Label { | 1387 | } |
2638 | 1427 | color: styleMusic.libraryEmpty.labelColor | 1388 | asynchronous: true |
2639 | 1428 | elide: Text.ElideRight | 1389 | source: "components/MusicToolbar.qml" |
2640 | 1429 | fontSize: "large" | 1390 | visible: mainPageStack.currentPage.title !== i18n.tr("Now playing") && |
2641 | 1430 | horizontalAlignment: Text.AlignLeft | 1391 | mainPageStack.currentPage.title !== i18n.tr("Queue") && |
2642 | 1431 | maximumLineCount: 4 | 1392 | mainPageStack.currentPage.title !== i18n.tr("Select playlist") && |
2643 | 1432 | text: i18n.tr("Connect your device to any computer and simply drag files to the Music folder or insert removable media with music.") | 1393 | !firstRun && |
2644 | 1433 | width: parent.width | 1394 | !wideAspect |
2645 | 1434 | wrapMode: Text.WordWrap | 1395 | z: 200 // put on top of everything else |
2646 | 1435 | } | 1396 | } |
2647 | 1436 | } | 1397 | |
2648 | 1437 | } | 1398 | PageStack { |
2649 | 1438 | 1399 | id: mainPageStack | |
2650 | 1439 | // Overlay to show when no playlists are on the device | 1400 | |
2651 | 1440 | Rectangle { | 1401 | // Properties storing the current page info |
2652 | 1441 | id: playlistsEmpty | 1402 | property Page currentMusicPage: null // currentPage can be Tabs |
2653 | 1403 | property bool popping: false | ||
2654 | 1404 | |||
2655 | 1405 | /* Helper functions */ | ||
2656 | 1406 | |||
2657 | 1407 | // Go back up the stack if possible | ||
2658 | 1408 | function goBack() { | ||
2659 | 1409 | if (depth > 1) { | ||
2660 | 1410 | pop() | ||
2661 | 1411 | } | ||
2662 | 1412 | } | ||
2663 | 1413 | |||
2664 | 1414 | // Pop a specific page in the stack | ||
2665 | 1415 | function popPage(page) { | ||
2666 | 1416 | var tmpPages = [] | ||
2667 | 1417 | |||
2668 | 1418 | popping = true | ||
2669 | 1419 | |||
2670 | 1420 | while (currentPage !== page && depth > 0) { | ||
2671 | 1421 | tmpPages.push(currentPage) | ||
2672 | 1422 | pop() | ||
2673 | 1423 | } | ||
2674 | 1424 | |||
2675 | 1425 | if (depth > 0) { | ||
2676 | 1426 | pop() | ||
2677 | 1427 | } | ||
2678 | 1428 | |||
2679 | 1429 | for (var i=tmpPages.length - 1; i > -1; i--) { | ||
2680 | 1430 | push(tmpPages[i]) | ||
2681 | 1431 | } | ||
2682 | 1432 | |||
2683 | 1433 | popping = false | ||
2684 | 1434 | } | ||
2685 | 1435 | |||
2686 | 1436 | // Set the current page, and any parent/stacks | ||
2687 | 1437 | function setPage(childPage) { | ||
2688 | 1438 | if (!popping) { | ||
2689 | 1439 | currentMusicPage = childPage; | ||
2690 | 1440 | } | ||
2691 | 1441 | } | ||
2692 | 1442 | |||
2693 | 1443 | Tabs { | ||
2694 | 1444 | id: tabs | ||
2695 | 1445 | anchors { | ||
2696 | 1446 | fill: parent | ||
2697 | 1447 | } | ||
2698 | 1448 | |||
2699 | 1449 | property Tab lastTab: selectedTab | ||
2700 | 1450 | |||
2701 | 1451 | onSelectedTabChanged: { | ||
2702 | 1452 | // pause loading of the models in the old tab | ||
2703 | 1453 | if (lastTab !== null && lastTab !== selectedTab) { | ||
2704 | 1454 | allowLoading(lastTab, false); | ||
2705 | 1455 | } | ||
2706 | 1456 | |||
2707 | 1457 | lastTab = selectedTab; | ||
2708 | 1458 | |||
2709 | 1459 | ensurePopulated(selectedTab); | ||
2710 | 1460 | } | ||
2711 | 1461 | |||
2712 | 1462 | onSelectedTabIndexChanged: { | ||
2713 | 1463 | if (loadedUI) { // store the tab index if changed by the user | ||
2714 | 1464 | startupSettings.tabIndex = selectedTabIndex | ||
2715 | 1465 | } | ||
2716 | 1466 | } | ||
2717 | 1467 | |||
2718 | 1468 | // Use a repeater to 'hide' the recent tab when the model is empty | ||
2719 | 1469 | // A repeater is used because the Tabs component respects adds and | ||
2720 | 1470 | // removes. Whereas replacing the list tabChildren does not appear | ||
2721 | 1471 | // to respect removes and setting the page as active: false causes | ||
2722 | 1472 | // the page to be blank but the action to still in the overflow | ||
2723 | 1473 | Repeater { | ||
2724 | 1474 | id: recentTabRepeater | ||
2725 | 1475 | // If the model has not loaded and at startup the db was not empty | ||
2726 | 1476 | // then show recent or | ||
2727 | 1477 | // If the workerlist has been set and it has values then show recent | ||
2728 | 1478 | model: (!recentModel.preLoadComplete && !startupRecentEmpty) || | ||
2729 | 1479 | (recentModel.workerList !== undefined && | ||
2730 | 1480 | recentModel.workerList.length > 0) ? 1 : 0 | ||
2731 | 1481 | delegate: Component { | ||
2732 | 1482 | // First tab is all music | ||
2733 | 1483 | Tab { | ||
2734 | 1484 | property bool populated: recentTabRepeater.populated | ||
2735 | 1485 | property var loader: [recentModel.filterRecent] | ||
2736 | 1486 | property bool loading: recentTabRepeater.loading | ||
2737 | 1487 | property var model: [recentModel, albumTracksModel] | ||
2738 | 1488 | id: recentTab | ||
2739 | 1489 | objectName: "recentTab" | ||
2740 | 1490 | anchors.fill: parent | ||
2741 | 1491 | title: page.title | ||
2742 | 1492 | |||
2743 | 1493 | // Tab content begins here | ||
2744 | 1494 | page: Recent { | ||
2745 | 1495 | id: recentPage | ||
2746 | 1496 | } | ||
2747 | 1497 | } | ||
2748 | 1498 | } | ||
2749 | 1499 | |||
2750 | 1500 | // Store the startup state of the db separately otherwise | ||
2751 | 1501 | // it breaks the binding of model | ||
2752 | 1502 | property bool startupRecentEmpty: Library.isRecentEmpty() | ||
2753 | 1503 | |||
2754 | 1504 | // cached values of the recent model that are copied when | ||
2755 | 1505 | // the tab is created | ||
2756 | 1506 | property bool loading: false | ||
2757 | 1507 | property bool populated: false | ||
2758 | 1508 | |||
2759 | 1509 | onCountChanged: { | ||
2760 | 1510 | if (count === 0 && loadedUI) { | ||
2761 | 1511 | // Jump to the albums tab when recent is empty | ||
2762 | 1512 | tabs.selectedTabIndex = albumsTab.index | ||
2763 | 1513 | } else if (count > 0 && !loadedUI) { | ||
2764 | 1514 | // UI is still loading and recent tab has been inserted | ||
2765 | 1515 | // so move the selected index 'down' as the value is | ||
2766 | 1516 | // not auto updated - this is for the case of loading | ||
2767 | 1517 | // directly to the recent tab (otherwise the content | ||
2768 | 1518 | // appears as the second tab but the tabs think they are | ||
2769 | 1519 | // on the first tab) | ||
2770 | 1520 | tabs.selectedTabIndex -= 1 | ||
2771 | 1521 | } else if (count > 0 && loadedUI) { | ||
2772 | 1522 | // tab inserted while the app is running so move the | ||
2773 | 1523 | // selected index 'up' to keep the same position | ||
2774 | 1524 | tabs.selectedTabIndex += 1 | ||
2775 | 1525 | } | ||
2776 | 1526 | } | ||
2777 | 1527 | } | ||
2778 | 1528 | |||
2779 | 1529 | // Second tab is arists | ||
2780 | 1530 | Tab { | ||
2781 | 1531 | property bool populated: true | ||
2782 | 1532 | property var loader: [] | ||
2783 | 1533 | property bool loading: false | ||
2784 | 1534 | property var model: [] | ||
2785 | 1535 | id: artistsTab | ||
2786 | 1536 | objectName: "artistsTab" | ||
2787 | 1537 | anchors.fill: parent | ||
2788 | 1538 | title: page.title | ||
2789 | 1539 | |||
2790 | 1540 | // tab content | ||
2791 | 1541 | page: Artists { | ||
2792 | 1542 | id: artistsPage | ||
2793 | 1543 | } | ||
2794 | 1544 | } | ||
2795 | 1545 | |||
2796 | 1546 | // third tab is albums | ||
2797 | 1547 | Tab { | ||
2798 | 1548 | property bool populated: true | ||
2799 | 1549 | property var loader: [] | ||
2800 | 1550 | property bool loading: false | ||
2801 | 1551 | property var model: [] | ||
2802 | 1552 | id: albumsTab | ||
2803 | 1553 | objectName: "albumsTab" | ||
2804 | 1554 | anchors.fill: parent | ||
2805 | 1555 | title: page.title | ||
2806 | 1556 | |||
2807 | 1557 | // Tab content begins here | ||
2808 | 1558 | page: Albums { | ||
2809 | 1559 | id: albumsPage | ||
2810 | 1560 | } | ||
2811 | 1561 | } | ||
2812 | 1562 | |||
2813 | 1563 | // forth tab is genres | ||
2814 | 1564 | Tab { | ||
2815 | 1565 | property bool populated: true | ||
2816 | 1566 | property var loader: [] | ||
2817 | 1567 | property bool loading: false | ||
2818 | 1568 | property var model: [] | ||
2819 | 1569 | id: genresTab | ||
2820 | 1570 | objectName: "genresTab" | ||
2821 | 1571 | anchors.fill: parent | ||
2822 | 1572 | title: page.title | ||
2823 | 1573 | |||
2824 | 1574 | // Tab content begins here | ||
2825 | 1575 | page: Genres { | ||
2826 | 1576 | id: genresPage | ||
2827 | 1577 | } | ||
2828 | 1578 | } | ||
2829 | 1579 | |||
2830 | 1580 | // fourth tab is all songs | ||
2831 | 1581 | Tab { | ||
2832 | 1582 | property bool populated: true | ||
2833 | 1583 | property var loader: [] | ||
2834 | 1584 | property bool loading: false | ||
2835 | 1585 | property var model: [] | ||
2836 | 1586 | id: songsTab | ||
2837 | 1587 | objectName: "songsTab" | ||
2838 | 1588 | anchors.fill: parent | ||
2839 | 1589 | title: page.title | ||
2840 | 1590 | |||
2841 | 1591 | // Tab content begins here | ||
2842 | 1592 | page: Songs { | ||
2843 | 1593 | id: tracksPage | ||
2844 | 1594 | } | ||
2845 | 1595 | } | ||
2846 | 1596 | |||
2847 | 1597 | |||
2848 | 1598 | // fifth tab is the playlists | ||
2849 | 1599 | Tab { | ||
2850 | 1600 | property bool populated: false | ||
2851 | 1601 | property var loader: [playlistModel.filterPlaylists] | ||
2852 | 1602 | property bool loading: false | ||
2853 | 1603 | property var model: [playlistModel, albumTracksModel] | ||
2854 | 1604 | id: playlistsTab | ||
2855 | 1605 | objectName: "playlistsTab" | ||
2856 | 1606 | anchors.fill: parent | ||
2857 | 1607 | title: page.title | ||
2858 | 1608 | |||
2859 | 1609 | // Tab content begins here | ||
2860 | 1610 | page: Playlists { | ||
2861 | 1611 | id: playlistsPage | ||
2862 | 1612 | } | ||
2863 | 1613 | } | ||
2864 | 1614 | |||
2865 | 1615 | // Set the models in the tab to allow/disallow loading | ||
2866 | 1616 | function allowLoading(tabToLoad, state) | ||
2867 | 1617 | { | ||
2868 | 1618 | if (tabToLoad !== undefined && tabToLoad.model !== undefined) | ||
2869 | 1619 | { | ||
2870 | 1620 | for (var i=0; i < tabToLoad.model.length; i++) | ||
2871 | 1621 | { | ||
2872 | 1622 | tabToLoad.model[i].canLoad = state; | ||
2873 | 1623 | } | ||
2874 | 1624 | } | ||
2875 | 1625 | } | ||
2876 | 1626 | |||
2877 | 1627 | function ensurePopulated(selectedTab) | ||
2878 | 1628 | { | ||
2879 | 1629 | allowLoading(selectedTab, true); // allow loading of the models | ||
2880 | 1630 | |||
2881 | 1631 | if (!selectedTab.populated && !selectedTab.loading && loadedUI) { | ||
2882 | 1632 | loading.visible = true | ||
2883 | 1633 | selectedTab.loading = true | ||
2884 | 1634 | |||
2885 | 1635 | if (selectedTab.loader !== undefined) | ||
2886 | 1636 | { | ||
2887 | 1637 | for (var i=0; i < selectedTab.loader.length; i++) | ||
2888 | 1638 | { | ||
2889 | 1639 | selectedTab.loader[i](); | ||
2890 | 1640 | } | ||
2891 | 1641 | } | ||
2892 | 1642 | } | ||
2893 | 1643 | loading.visible = selectedTab.loading || !selectedTab.populated | ||
2894 | 1644 | } | ||
2895 | 1645 | |||
2896 | 1646 | function pushNowPlaying() | ||
2897 | 1647 | { | ||
2898 | 1648 | // only push if on a different page | ||
2899 | 1649 | if (mainPageStack.currentPage.title !== i18n.tr("Now playing") | ||
2900 | 1650 | && mainPageStack.currentPage.title !== i18n.tr("Queue")) { | ||
2901 | 1651 | mainPageStack.push(Qt.resolvedUrl("components/NowPlaying.qml"), {}) | ||
2902 | 1652 | } | ||
2903 | 1653 | |||
2904 | 1654 | if (mainPageStack.currentPage.title === i18n.tr("Queue")) { | ||
2905 | 1655 | mainPageStack.currentPage.isListView = false; // ensure full view | ||
2906 | 1656 | } | ||
2907 | 1657 | } | ||
2908 | 1658 | } // end of tabs | ||
2909 | 1659 | } | ||
2910 | 1660 | |||
2911 | 1661 | Loader { | ||
2912 | 1662 | id: emptyPageLoader | ||
2913 | 1663 | // Do not be active if content-hub is importing due to the models resetting | ||
2914 | 1664 | // this then causes the empty page loader to partially run then showing a blank header | ||
2915 | 1665 | active: noMusic && !firstRun && contentHubWaitForFile.processId === -1 | ||
2916 | 1442 | anchors { | 1666 | anchors { |
2917 | 1443 | fill: parent | 1667 | fill: parent |
2955 | 1444 | topMargin: -emptyPage.header.height | 1668 | } |
2956 | 1445 | } | 1669 | source: "ui/LibraryEmptyState.qml" |
2957 | 1446 | color: mainView.backgroundColor | 1670 | visible: active |
2958 | 1447 | visible: emptyPage.noPlaylists && !emptyPage.noMusic && (playlistTab.index === tabs.selectedTab.index || mainPageStack.currentPage.title === i18n.tr("Select playlist")) | 1671 | |
2959 | 1448 | 1672 | property bool noMusic: allSongsModel.rowCount === 0 && allSongsModelModel.status === SongsModel.Ready && loadedUI | |
2960 | 1449 | Column { | 1673 | } |
2961 | 1450 | anchors.centerIn: parent | 1674 | |
2962 | 1451 | spacing: units.gu(4) | 1675 | LoadingSpinnerComponent { |
2963 | 1452 | width: units.gu(36) | 1676 | id: loading |
2964 | 1453 | 1677 | } | |
2928 | 1454 | Label { | ||
2929 | 1455 | color: styleMusic.libraryEmpty.labelColor | ||
2930 | 1456 | elide: Text.ElideRight | ||
2931 | 1457 | fontSize: "x-large" | ||
2932 | 1458 | horizontalAlignment: Text.AlignLeft | ||
2933 | 1459 | maximumLineCount: 2 | ||
2934 | 1460 | text: i18n.tr("No playlists found") | ||
2935 | 1461 | width: parent.width | ||
2936 | 1462 | wrapMode: Text.WordWrap | ||
2937 | 1463 | } | ||
2938 | 1464 | |||
2939 | 1465 | Label { | ||
2940 | 1466 | color: styleMusic.libraryEmpty.labelColor | ||
2941 | 1467 | elide: Text.ElideRight | ||
2942 | 1468 | fontSize: "large" | ||
2943 | 1469 | horizontalAlignment: Text.AlignLeft | ||
2944 | 1470 | maximumLineCount: 4 | ||
2945 | 1471 | text: i18n.tr("Get more out of Music by tapping the %1 icon to start making playlists for every mood and occasion.").arg('"+"') | ||
2946 | 1472 | width: parent.width | ||
2947 | 1473 | wrapMode: Text.WordWrap | ||
2948 | 1474 | } | ||
2949 | 1475 | } | ||
2950 | 1476 | } | ||
2951 | 1477 | } | ||
2952 | 1478 | |||
2953 | 1479 | LoadingSpinnerComponent { | ||
2954 | 1480 | id: loading | ||
2965 | 1481 | } | 1678 | } |
2966 | 1482 | } // end of main view | 1679 | } // end of main view |
2967 | 1483 | 1680 | ||
2968 | === added directory 'app/ui' | |||
2969 | === renamed file 'MusicaddtoPlaylist.qml' => 'app/ui/AddToPlaylist.qml' | |||
2970 | --- MusicaddtoPlaylist.qml 2015-01-28 02:27:52 +0000 | |||
2971 | +++ app/ui/AddToPlaylist.qml 2015-02-10 03:13:44 +0000 | |||
2972 | @@ -23,9 +23,11 @@ | |||
2973 | 23 | import Ubuntu.Components.ListItems 1.0 as ListItem | 23 | import Ubuntu.Components.ListItems 1.0 as ListItem |
2974 | 24 | import Ubuntu.Components.Popups 1.0 | 24 | import Ubuntu.Components.Popups 1.0 |
2975 | 25 | import QtQuick.LocalStorage 2.0 | 25 | import QtQuick.LocalStorage 2.0 |
2979 | 26 | import "meta-database.js" as Library | 26 | import "../logic/meta-database.js" as Library |
2980 | 27 | import "playlists.js" as Playlists | 27 | import "../logic/playlists.js" as Playlists |
2981 | 28 | import "common" | 28 | import "../components" |
2982 | 29 | import "../components/Flickables" | ||
2983 | 30 | import "../components/HeadState" | ||
2984 | 29 | 31 | ||
2985 | 30 | 32 | ||
2986 | 31 | /* NOTE: | 33 | /* NOTE: |
2987 | @@ -45,25 +47,10 @@ | |||
2988 | 45 | searchResultsCount: addToPlaylistModelFilter.count | 47 | searchResultsCount: addToPlaylistModelFilter.count |
2989 | 46 | state: "default" | 48 | state: "default" |
2990 | 47 | states: [ | 49 | states: [ |
3010 | 48 | PageHeadState { | 50 | PlaylistsHeadState { |
3011 | 49 | name: "default" | 51 | newPlaylistEnabled: allSongsModel.count > 0 |
3012 | 50 | head: addToPlaylistPage.head | 52 | searchEnabled: playlistModel.model.count > 0 && allSongsModel.count > 0 |
3013 | 51 | actions: [ | 53 | thisPage: addToPlaylistPage |
2995 | 52 | Action { | ||
2996 | 53 | enabled: allSongsModel.count > 0 | ||
2997 | 54 | objectName: "newPlaylistButton" | ||
2998 | 55 | iconName: "add" | ||
2999 | 56 | onTriggered: { | ||
3000 | 57 | customdebug("New playlist.") | ||
3001 | 58 | PopupUtils.open(newPlaylistDialog, mainView) | ||
3002 | 59 | } | ||
3003 | 60 | }, | ||
3004 | 61 | Action { | ||
3005 | 62 | enabled: playlistModel.model.count > 0 && allSongsModel.count > 0 | ||
3006 | 63 | iconName: "search" | ||
3007 | 64 | onTriggered: addToPlaylistPage.state = "search" | ||
3008 | 65 | } | ||
3009 | 66 | ] | ||
3014 | 67 | }, | 54 | }, |
3015 | 68 | SearchHeadState { | 55 | SearchHeadState { |
3016 | 69 | id: searchHeader | 56 | id: searchHeader |
3017 | @@ -129,8 +116,20 @@ | |||
3018 | 129 | page.covers = Playlists.getPlaylistCovers(name) | 116 | page.covers = Playlists.getPlaylistCovers(name) |
3019 | 130 | } | 117 | } |
3020 | 131 | 118 | ||
3022 | 132 | musicToolbar.goBack(); // go back to the previous page | 119 | mainPageStack.goBack(); // go back to the previous page |
3023 | 133 | } | 120 | } |
3024 | 134 | } | 121 | } |
3025 | 135 | } | 122 | } |
3026 | 123 | |||
3027 | 124 | // Overlay to show when no playlists are on the device | ||
3028 | 125 | Loader { | ||
3029 | 126 | anchors { | ||
3030 | 127 | fill: parent | ||
3031 | 128 | topMargin: -playlistsPage.header.height | ||
3032 | 129 | } | ||
3033 | 130 | active: playlistModel.model.count === 0 && playlistModel.workerComplete | ||
3034 | 131 | asynchronous: true | ||
3035 | 132 | source: "../components/PlaylistsEmptyState.qml" | ||
3036 | 133 | visible: active | ||
3037 | 134 | } | ||
3038 | 136 | } | 135 | } |
3039 | 137 | 136 | ||
3040 | === renamed file 'MusicAlbums.qml' => 'app/ui/Albums.qml' | |||
3041 | --- MusicAlbums.qml 2015-01-20 12:02:52 +0000 | |||
3042 | +++ app/ui/Albums.qml 2015-02-10 03:13:44 +0000 | |||
3043 | @@ -20,7 +20,9 @@ | |||
3044 | 20 | import QtQuick 2.3 | 20 | import QtQuick 2.3 |
3045 | 21 | import Ubuntu.Components 1.1 | 21 | import Ubuntu.Components 1.1 |
3046 | 22 | import Ubuntu.MediaScanner 0.1 | 22 | import Ubuntu.MediaScanner 0.1 |
3048 | 23 | import "common" | 23 | import "../components" |
3049 | 24 | import "../components/Flickables" | ||
3050 | 25 | import "../components/HeadState" | ||
3051 | 24 | 26 | ||
3052 | 25 | 27 | ||
3053 | 26 | MusicPage { | 28 | MusicPage { |
3054 | @@ -31,14 +33,9 @@ | |||
3055 | 31 | searchResultsCount: albumsModelFilter.count | 33 | searchResultsCount: albumsModelFilter.count |
3056 | 32 | state: "default" | 34 | state: "default" |
3057 | 33 | states: [ | 35 | states: [ |
3066 | 34 | PageHeadState { | 36 | SearchableHeadState { |
3067 | 35 | name: "default" | 37 | thisPage: albumsPage |
3068 | 36 | head: albumsPage.head | 38 | searchEnabled: albumsModelFilter.count > 0 |
3061 | 37 | actions: Action { | ||
3062 | 38 | enabled: albumsModelFilter.count > 0 | ||
3063 | 39 | iconName: "search" | ||
3064 | 40 | onTriggered: albumsPage.state = "search" | ||
3065 | 41 | } | ||
3069 | 42 | }, | 39 | }, |
3070 | 43 | SearchHeadState { | 40 | SearchHeadState { |
3071 | 44 | id: searchHeader | 41 | id: searchHeader |
3072 | @@ -46,6 +43,11 @@ | |||
3073 | 46 | } | 43 | } |
3074 | 47 | ] | 44 | ] |
3075 | 48 | 45 | ||
3076 | 46 | // Hack for autopilot otherwise Albums appears as MusicPage | ||
3077 | 47 | // due to bug 1341671 it is required that there is a property so that | ||
3078 | 48 | // qml doesn't optimise using the parent type | ||
3079 | 49 | property bool bug1341671workaround: true | ||
3080 | 50 | |||
3081 | 49 | CardView { | 51 | CardView { |
3082 | 50 | id: albumCardView | 52 | id: albumCardView |
3083 | 51 | model: SortFilterModel { | 53 | model: SortFilterModel { |
3084 | @@ -70,24 +72,17 @@ | |||
3085 | 70 | secondaryText: model.artist != "" ? model.artist : i18n.tr("Unknown Artist") | 72 | secondaryText: model.artist != "" ? model.artist : i18n.tr("Unknown Artist") |
3086 | 71 | 73 | ||
3087 | 72 | onClicked: { | 74 | onClicked: { |
3106 | 73 | var comp = Qt.createComponent("common/SongsPage.qml") | 75 | mainPageStack.push(Qt.resolvedUrl("SongsView.qml"), |
3107 | 74 | var songsPage = comp.createObject(mainPageStack, | 76 | { |
3108 | 75 | { | 77 | "album": model.title, |
3109 | 76 | "album": model.title, | 78 | "artist": model.artist, |
3110 | 77 | "artist": model.artist, | 79 | "covers": [{art: model.art}], |
3111 | 78 | "covers": [{art: model.art}], | 80 | "isAlbum": true, |
3112 | 79 | "isAlbum": true, | 81 | "genre": undefined, |
3113 | 80 | "genre": undefined, | 82 | "title": i18n.tr("Album"), |
3114 | 81 | "title": i18n.tr("Album"), | 83 | "line1": model.artist, |
3115 | 82 | "line1": model.artist, | 84 | "line2": model.title |
3116 | 83 | "line2": model.title, | 85 | }) |
3099 | 84 | }); | ||
3100 | 85 | |||
3101 | 86 | if (songsPage == null) { // Error Handling | ||
3102 | 87 | console.log("Error creating object"); | ||
3103 | 88 | } | ||
3104 | 89 | |||
3105 | 90 | mainPageStack.push(songsPage) | ||
3117 | 91 | } | 86 | } |
3118 | 92 | } | 87 | } |
3119 | 93 | } | 88 | } |
3120 | 94 | 89 | ||
3121 | === renamed file 'common/AlbumsPage.qml' => 'app/ui/ArtistView.qml' | |||
3122 | --- common/AlbumsPage.qml 2015-01-30 01:23:39 +0000 | |||
3123 | +++ app/ui/ArtistView.qml 2015-02-10 03:13:44 +0000 | |||
3124 | @@ -24,11 +24,14 @@ | |||
3125 | 24 | import Ubuntu.MediaScanner 0.1 | 24 | import Ubuntu.MediaScanner 0.1 |
3126 | 25 | import Ubuntu.Thumbnailer 0.1 | 25 | import Ubuntu.Thumbnailer 0.1 |
3127 | 26 | import QtQuick.LocalStorage 2.0 | 26 | import QtQuick.LocalStorage 2.0 |
3129 | 27 | import "../meta-database.js" as Library | 27 | import "../logic/meta-database.js" as Library |
3130 | 28 | import "../components" | ||
3131 | 29 | import "../components/Flickables" | ||
3132 | 30 | import "../components/ViewButton" | ||
3133 | 28 | 31 | ||
3134 | 29 | MusicPage { | 32 | MusicPage { |
3137 | 30 | id: albumStackPage | 33 | id: artistViewPage |
3138 | 31 | objectName: "albumsArtistPage" | 34 | objectName: "artistViewPage" |
3139 | 32 | visible: false | 35 | visible: false |
3140 | 33 | 36 | ||
3141 | 34 | property string artist: "" | 37 | property string artist: "" |
3142 | @@ -50,57 +53,17 @@ | |||
3143 | 50 | header: BlurredHeader { | 53 | header: BlurredHeader { |
3144 | 51 | rightColumn: Column { | 54 | rightColumn: Column { |
3145 | 52 | spacing: units.gu(2) | 55 | spacing: units.gu(2) |
3194 | 53 | Button { | 56 | ShuffleButton { |
3195 | 54 | id: shuffleRow | 57 | model: songArtistModel |
3196 | 55 | height: units.gu(4) | 58 | } |
3197 | 56 | strokeColor: UbuntuColors.green | 59 | QueueAllButton { |
3198 | 57 | width: units.gu(15) | 60 | model: songArtistModel |
3199 | 58 | Text { | 61 | } |
3200 | 59 | anchors { | 62 | PlayAllButton { |
3201 | 60 | centerIn: parent | 63 | model: songArtistModel |
3154 | 61 | } | ||
3155 | 62 | color: "white" | ||
3156 | 63 | elide: Text.ElideRight | ||
3157 | 64 | height: parent.height | ||
3158 | 65 | horizontalAlignment: Text.AlignHCenter | ||
3159 | 66 | // TRANSLATORS: this appears in a button with limited space (around 14 characters) | ||
3160 | 67 | text: i18n.tr("Shuffle") | ||
3161 | 68 | verticalAlignment: Text.AlignVCenter | ||
3162 | 69 | width: parent.width - units.gu(2) | ||
3163 | 70 | } | ||
3164 | 71 | onClicked: shuffleModel(songArtistModel) | ||
3165 | 72 | } | ||
3166 | 73 | Button { | ||
3167 | 74 | id: queueAllRow | ||
3168 | 75 | height: units.gu(4) | ||
3169 | 76 | strokeColor: UbuntuColors.green | ||
3170 | 77 | width: units.gu(15) | ||
3171 | 78 | Text { | ||
3172 | 79 | anchors { | ||
3173 | 80 | centerIn: parent | ||
3174 | 81 | } | ||
3175 | 82 | color: "white" | ||
3176 | 83 | elide: Text.ElideRight | ||
3177 | 84 | height: parent.height | ||
3178 | 85 | horizontalAlignment: Text.AlignHCenter | ||
3179 | 86 | // TRANSLATORS: this appears in a button with limited space (around 14 characters) | ||
3180 | 87 | text: i18n.tr("Queue all") | ||
3181 | 88 | verticalAlignment: Text.AlignVCenter | ||
3182 | 89 | width: parent.width - units.gu(2) | ||
3183 | 90 | } | ||
3184 | 91 | onClicked: addQueueFromModel(songArtistModel) | ||
3185 | 92 | } | ||
3186 | 93 | Button { | ||
3187 | 94 | id: playRow | ||
3188 | 95 | color: UbuntuColors.green | ||
3189 | 96 | height: units.gu(4) | ||
3190 | 97 | // TRANSLATORS: this appears in a button with limited space (around 14 characters) | ||
3191 | 98 | text: i18n.tr("Play all") | ||
3192 | 99 | width: units.gu(15) | ||
3193 | 100 | onClicked: trackClicked(songArtistModel, 0, true) | ||
3202 | 101 | } | 64 | } |
3203 | 102 | } | 65 | } |
3205 | 103 | coverSources: albumStackPage.covers | 66 | coverSources: artistViewPage.covers |
3206 | 104 | height: units.gu(30) | 67 | height: units.gu(30) |
3207 | 105 | bottomColumn: Column { | 68 | bottomColumn: Column { |
3208 | 106 | Label { | 69 | Label { |
3209 | @@ -139,18 +102,18 @@ | |||
3210 | 139 | 102 | ||
3211 | 140 | SongsModel { | 103 | SongsModel { |
3212 | 141 | id: songArtistModel | 104 | id: songArtistModel |
3214 | 142 | albumArtist: albumStackPage.artist | 105 | albumArtist: artistViewPage.artist |
3215 | 143 | store: musicStore | 106 | store: musicStore |
3216 | 144 | } | 107 | } |
3217 | 145 | } | 108 | } |
3218 | 146 | itemWidth: units.gu(12) | 109 | itemWidth: units.gu(12) |
3219 | 147 | model: AlbumsModel { | 110 | model: AlbumsModel { |
3220 | 148 | id: albumsModel | 111 | id: albumsModel |
3222 | 149 | albumArtist: albumStackPage.artist | 112 | albumArtist: artistViewPage.artist |
3223 | 150 | store: musicStore | 113 | store: musicStore |
3224 | 151 | onStatusChanged: { | 114 | onStatusChanged: { |
3225 | 152 | if (albumsModel.status === SongsModel.Ready && loaded && albumsModel.count === 0) { | 115 | if (albumsModel.status === SongsModel.Ready && loaded && albumsModel.count === 0) { |
3227 | 153 | musicToolbar.popPage(albumStackPage) | 116 | mainPageStack.popPage(artistViewPage) |
3228 | 154 | } | 117 | } |
3229 | 155 | } | 118 | } |
3230 | 156 | } | 119 | } |
3231 | @@ -162,24 +125,17 @@ | |||
3232 | 162 | secondaryTextVisible: false | 125 | secondaryTextVisible: false |
3233 | 163 | 126 | ||
3234 | 164 | onClicked: { | 127 | onClicked: { |
3253 | 165 | var comp = Qt.createComponent("SongsPage.qml") | 128 | mainPageStack.push(Qt.resolvedUrl("SongsView.qml"), |
3254 | 166 | var songsPage = comp.createObject(mainPageStack, | 129 | { |
3255 | 167 | { | 130 | "album": model.title, |
3256 | 168 | "album": model.title, | 131 | "artist": model.artist, |
3257 | 169 | "artist": model.artist, | 132 | "covers": [{art: model.art}], |
3258 | 170 | "covers": [{art: model.art}], | 133 | "isAlbum": true, |
3259 | 171 | "isAlbum": true, | 134 | "genre": undefined, |
3260 | 172 | "genre": undefined, | 135 | "title": i18n.tr("Album"), |
3261 | 173 | "title": i18n.tr("Album"), | 136 | "line1": model.artist != "" ? model.artist : i18n.tr("Unknown Artist"), |
3262 | 174 | "line1": model.artist != "" ? model.artist : i18n.tr("Unknown Artist"), | 137 | "line2": model.title != "" ? model.title : i18n.tr("Unknown Album") |
3263 | 175 | "line2": model.title != "" ? model.title : i18n.tr("Unknown Album"), | 138 | }) |
3246 | 176 | }); | ||
3247 | 177 | |||
3248 | 178 | if (songsPage == null) { // Error Handling | ||
3249 | 179 | console.log("Error creating object"); | ||
3250 | 180 | } | ||
3251 | 181 | |||
3252 | 182 | mainPageStack.push(songsPage) | ||
3264 | 183 | } | 139 | } |
3265 | 184 | } | 140 | } |
3266 | 185 | } | 141 | } |
3267 | 186 | 142 | ||
3268 | === renamed file 'MusicArtists.qml' => 'app/ui/Artists.qml' | |||
3269 | --- MusicArtists.qml 2015-01-20 12:02:52 +0000 | |||
3270 | +++ app/ui/Artists.qml 2015-02-10 03:13:44 +0000 | |||
3271 | @@ -24,9 +24,11 @@ | |||
3272 | 24 | import Ubuntu.MediaScanner 0.1 | 24 | import Ubuntu.MediaScanner 0.1 |
3273 | 25 | import Ubuntu.Thumbnailer 0.1 | 25 | import Ubuntu.Thumbnailer 0.1 |
3274 | 26 | import QtQuick.LocalStorage 2.0 | 26 | import QtQuick.LocalStorage 2.0 |
3278 | 27 | import "meta-database.js" as Library | 27 | import "../logic/meta-database.js" as Library |
3279 | 28 | import "playlists.js" as Playlists | 28 | import "../logic/playlists.js" as Playlists |
3280 | 29 | import "common" | 29 | import "../components" |
3281 | 30 | import "../components/Flickables" | ||
3282 | 31 | import "../components/HeadState" | ||
3283 | 30 | 32 | ||
3284 | 31 | 33 | ||
3285 | 32 | MusicPage { | 34 | MusicPage { |
3286 | @@ -37,14 +39,9 @@ | |||
3287 | 37 | searchResultsCount: artistsModelFilter.count | 39 | searchResultsCount: artistsModelFilter.count |
3288 | 38 | state: "default" | 40 | state: "default" |
3289 | 39 | states: [ | 41 | states: [ |
3298 | 40 | PageHeadState { | 42 | SearchableHeadState { |
3299 | 41 | name: "default" | 43 | thisPage: artistsPage |
3300 | 42 | head: artistsPage.head | 44 | searchEnabled: artistsModelFilter.count > 0 |
3293 | 43 | actions: Action { | ||
3294 | 44 | enabled: artistsModelFilter.count > 0 | ||
3295 | 45 | iconName: "search" | ||
3296 | 46 | onTriggered: artistsPage.state = "search" | ||
3297 | 47 | } | ||
3301 | 48 | }, | 45 | }, |
3302 | 49 | SearchHeadState { | 46 | SearchHeadState { |
3303 | 50 | id: searchHeader | 47 | id: searchHeader |
3304 | @@ -52,6 +49,11 @@ | |||
3305 | 52 | } | 49 | } |
3306 | 53 | ] | 50 | ] |
3307 | 54 | 51 | ||
3308 | 52 | // Hack for autopilot otherwise Artists appears as MusicPage | ||
3309 | 53 | // due to bug 1341671 it is required that there is a property so that | ||
3310 | 54 | // qml doesn't optimise using the parent type | ||
3311 | 55 | property bool bug1341671workaround: true | ||
3312 | 56 | |||
3313 | 55 | CardView { | 57 | CardView { |
3314 | 56 | id: artistCardView | 58 | id: artistCardView |
3315 | 57 | itemWidth: units.gu(12) | 59 | itemWidth: units.gu(12) |
3316 | @@ -97,21 +99,13 @@ | |||
3317 | 97 | } | 99 | } |
3318 | 98 | } | 100 | } |
3319 | 99 | 101 | ||
3320 | 100 | |||
3321 | 101 | onClicked: { | 102 | onClicked: { |
3335 | 102 | var comp = Qt.createComponent("common/AlbumsPage.qml") | 103 | mainPageStack.push(Qt.resolvedUrl("ArtistView.qml"), |
3336 | 103 | var albumsPage = comp.createObject(mainPageStack, | 104 | { |
3337 | 104 | { | 105 | "artist": model.artist, |
3338 | 105 | "artist": model.artist, | 106 | "covers": artistCard.coverSources, |
3339 | 106 | "covers": artistCard.coverSources, | 107 | "title": i18n.tr("Artist") |
3340 | 107 | "title": i18n.tr("Artist"), | 108 | }) |
3328 | 108 | }); | ||
3329 | 109 | |||
3330 | 110 | if (albumsPage == null) { // Error Handling | ||
3331 | 111 | console.log("Error creating object"); | ||
3332 | 112 | } | ||
3333 | 113 | |||
3334 | 114 | mainPageStack.push(albumsPage) | ||
3341 | 115 | } | 109 | } |
3342 | 116 | } | 110 | } |
3343 | 117 | } | 111 | } |
3344 | 118 | 112 | ||
3345 | === added file 'app/ui/CMakeLists.txt' | |||
3346 | --- app/ui/CMakeLists.txt 1970-01-01 00:00:00 +0000 | |||
3347 | +++ app/ui/CMakeLists.txt 2015-02-10 03:13:44 +0000 | |||
3348 | @@ -0,0 +1,4 @@ | |||
3349 | 1 | # make the qml files visible on qtcreator | ||
3350 | 2 | file(GLOB UI_QML_FILES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.qml) | ||
3351 | 3 | |||
3352 | 4 | add_custom_target(com_ubuntu_music_UI_QMLFiles ALL SOURCES ${UI_QML_FILES}) | ||
3353 | 0 | 5 | ||
3354 | === renamed file 'MusicGenres.qml' => 'app/ui/Genres.qml' | |||
3355 | --- MusicGenres.qml 2015-01-20 12:02:52 +0000 | |||
3356 | +++ app/ui/Genres.qml 2015-02-10 03:13:44 +0000 | |||
3357 | @@ -20,7 +20,9 @@ | |||
3358 | 20 | import QtQuick 2.3 | 20 | import QtQuick 2.3 |
3359 | 21 | import Ubuntu.Components 1.1 | 21 | import Ubuntu.Components 1.1 |
3360 | 22 | import Ubuntu.MediaScanner 0.1 | 22 | import Ubuntu.MediaScanner 0.1 |
3362 | 23 | import "common" | 23 | import "../components" |
3363 | 24 | import "../components/Flickables" | ||
3364 | 25 | import "../components/HeadState" | ||
3365 | 24 | 26 | ||
3366 | 25 | 27 | ||
3367 | 26 | MusicPage { | 28 | MusicPage { |
3368 | @@ -31,14 +33,9 @@ | |||
3369 | 31 | searchResultsCount: genresModelFilter.count | 33 | searchResultsCount: genresModelFilter.count |
3370 | 32 | state: "default" | 34 | state: "default" |
3371 | 33 | states: [ | 35 | states: [ |
3380 | 34 | PageHeadState { | 36 | SearchableHeadState { |
3381 | 35 | name: "default" | 37 | thisPage: genresPage |
3382 | 36 | head: genresPage.head | 38 | searchEnabled: genresModelFilter.count > 0 |
3375 | 37 | actions: Action { | ||
3376 | 38 | enabled: genresModelFilter.count > 0 | ||
3377 | 39 | iconName: "search" | ||
3378 | 40 | onTriggered: genresPage.state = "search" | ||
3379 | 41 | } | ||
3383 | 42 | }, | 39 | }, |
3384 | 43 | SearchHeadState { | 40 | SearchHeadState { |
3385 | 44 | id: searchHeader | 41 | id: searchHeader |
3386 | @@ -46,6 +43,11 @@ | |||
3387 | 46 | } | 43 | } |
3388 | 47 | ] | 44 | ] |
3389 | 48 | 45 | ||
3390 | 46 | // Hack for autopilot otherwise Albums appears as MusicPage | ||
3391 | 47 | // due to bug 1341671 it is required that there is a property so that | ||
3392 | 48 | // qml doesn't optimise using the parent type | ||
3393 | 49 | property bool bug1341671workaround: true | ||
3394 | 50 | |||
3395 | 49 | CardView { | 51 | CardView { |
3396 | 50 | id: genreCardView | 52 | id: genreCardView |
3397 | 51 | itemWidth: units.gu(12) | 53 | itemWidth: units.gu(12) |
3398 | @@ -98,23 +100,16 @@ | |||
3399 | 98 | } | 100 | } |
3400 | 99 | 101 | ||
3401 | 100 | onClicked: { | 102 | onClicked: { |
3419 | 101 | var comp = Qt.createComponent("common/SongsPage.qml") | 103 | mainPageStack.push(Qt.resolvedUrl("SongsView.qml"), |
3420 | 102 | var songsPage = comp.createObject(mainPageStack, | 104 | { |
3421 | 103 | { | 105 | "covers": genreCard.coverSources, |
3422 | 104 | "covers": genreCard.coverSources, | 106 | "album": undefined, |
3423 | 105 | "album": undefined, | 107 | "isAlbum": true, |
3424 | 106 | "isAlbum": true, | 108 | "genre": model.genre, |
3425 | 107 | "genre": model.genre, | 109 | "title": i18n.tr("Genre"), |
3426 | 108 | "title": i18n.tr("Genre"), | 110 | "line2": model.genre, |
3427 | 109 | "line2": model.genre, | 111 | "line1": i18n.tr("Genre") |
3428 | 110 | "line1": i18n.tr("Genre") | 112 | }) |
3412 | 111 | }); | ||
3413 | 112 | |||
3414 | 113 | if (songsPage == null) { // Error Handling | ||
3415 | 114 | console.log("Error creating object"); | ||
3416 | 115 | } | ||
3417 | 116 | |||
3418 | 117 | mainPageStack.push(songsPage) | ||
3429 | 118 | } | 113 | } |
3430 | 119 | } | 114 | } |
3431 | 120 | } | 115 | } |
3432 | 121 | 116 | ||
3433 | === added file 'app/ui/LibraryEmptyState.qml' | |||
3434 | --- app/ui/LibraryEmptyState.qml 1970-01-01 00:00:00 +0000 | |||
3435 | +++ app/ui/LibraryEmptyState.qml 2015-02-10 03:13:44 +0000 | |||
3436 | @@ -0,0 +1,123 @@ | |||
3437 | 1 | /* | ||
3438 | 2 | * Copyright (C) 2013, 2014, 2015 | ||
3439 | 3 | * Andrew Hayzen <ahayzen@gmail.com> | ||
3440 | 4 | * Daniel Holm <d.holmen@gmail.com> | ||
3441 | 5 | * Victor Thompson <victor.thompson@gmail.com> | ||
3442 | 6 | * | ||
3443 | 7 | * This program is free software; you can redistribute it and/or modify | ||
3444 | 8 | * it under the terms of the GNU General Public License as published by | ||
3445 | 9 | * the Free Software Foundation; version 3. | ||
3446 | 10 | * | ||
3447 | 11 | * This program is distributed in the hope that it will be useful, | ||
3448 | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
3449 | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
3450 | 14 | * GNU General Public License for more details. | ||
3451 | 15 | * | ||
3452 | 16 | * You should have received a copy of the GNU General Public License | ||
3453 | 17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
3454 | 18 | */ | ||
3455 | 19 | |||
3456 | 20 | import QtQuick 2.3 | ||
3457 | 21 | import Ubuntu.Components 1.1 | ||
3458 | 22 | |||
3459 | 23 | Page { | ||
3460 | 24 | id: libraryEmptyPage | ||
3461 | 25 | anchors { | ||
3462 | 26 | fill: parent | ||
3463 | 27 | } | ||
3464 | 28 | |||
3465 | 29 | // Overlay to show when no tracks detected on the device | ||
3466 | 30 | Rectangle { | ||
3467 | 31 | id: libraryEmpty | ||
3468 | 32 | anchors { | ||
3469 | 33 | fill: parent | ||
3470 | 34 | topMargin: -libraryEmptyPage.header.height | ||
3471 | 35 | } | ||
3472 | 36 | color: mainView.backgroundColor | ||
3473 | 37 | |||
3474 | 38 | Column { | ||
3475 | 39 | id: noMusicTextColumn | ||
3476 | 40 | anchors { | ||
3477 | 41 | centerIn: parent | ||
3478 | 42 | } | ||
3479 | 43 | spacing: units.gu(4) | ||
3480 | 44 | width: units.gu(36) | ||
3481 | 45 | |||
3482 | 46 | Row { | ||
3483 | 47 | anchors { | ||
3484 | 48 | horizontalCenter: parent.horizontalCenter | ||
3485 | 49 | } | ||
3486 | 50 | |||
3487 | 51 | Item { | ||
3488 | 52 | height: parent.height | ||
3489 | 53 | width: imageEmptyDownload.width + units.gu(2) | ||
3490 | 54 | |||
3491 | 55 | Image { | ||
3492 | 56 | id: imageEmptyDownload | ||
3493 | 57 | anchors { | ||
3494 | 58 | horizontalCenter: parent.horizontalCenter | ||
3495 | 59 | verticalCenter: parent.verticalCenter | ||
3496 | 60 | } | ||
3497 | 61 | antialiasing: true | ||
3498 | 62 | fillMode: Image.PreserveAspectFit | ||
3499 | 63 | height: units.gu(10) | ||
3500 | 64 | smooth: true | ||
3501 | 65 | source: "../graphics/music_empty_download.png" | ||
3502 | 66 | } | ||
3503 | 67 | } | ||
3504 | 68 | |||
3505 | 69 | Item { | ||
3506 | 70 | height: parent.height | ||
3507 | 71 | width: units.gu(7) | ||
3508 | 72 | |||
3509 | 73 | Image { | ||
3510 | 74 | id: imageSep | ||
3511 | 75 | anchors { | ||
3512 | 76 | horizontalCenter: parent.horizontalCenter | ||
3513 | 77 | verticalCenter: parent.verticalCenter | ||
3514 | 78 | } | ||
3515 | 79 | antialiasing: true | ||
3516 | 80 | fillMode: Image.PreserveAspectFit | ||
3517 | 81 | height: units.gu(6) | ||
3518 | 82 | smooth: true | ||
3519 | 83 | source: "../graphics/div.png" | ||
3520 | 84 | } | ||
3521 | 85 | } | ||
3522 | 86 | |||
3523 | 87 | Image { | ||
3524 | 88 | id: imageEmptySD | ||
3525 | 89 | anchors { | ||
3526 | 90 | verticalCenter: parent.verticalCenter | ||
3527 | 91 | } | ||
3528 | 92 | antialiasing: true | ||
3529 | 93 | fillMode: Image.PreserveAspectFit | ||
3530 | 94 | height: units.gu(7) | ||
3531 | 95 | smooth: true | ||
3532 | 96 | source: "../graphics/music_empty_SD.png" | ||
3533 | 97 | } | ||
3534 | 98 | } | ||
3535 | 99 | |||
3536 | 100 | Label { | ||
3537 | 101 | color: styleMusic.libraryEmpty.labelColor | ||
3538 | 102 | elide: Text.ElideRight | ||
3539 | 103 | fontSize: "x-large" | ||
3540 | 104 | horizontalAlignment: Text.AlignLeft | ||
3541 | 105 | maximumLineCount: 2 | ||
3542 | 106 | text: i18n.tr("No music found") | ||
3543 | 107 | width: parent.width | ||
3544 | 108 | wrapMode: Text.WordWrap | ||
3545 | 109 | } | ||
3546 | 110 | |||
3547 | 111 | Label { | ||
3548 | 112 | color: styleMusic.libraryEmpty.labelColor | ||
3549 | 113 | elide: Text.ElideRight | ||
3550 | 114 | fontSize: "large" | ||
3551 | 115 | horizontalAlignment: Text.AlignLeft | ||
3552 | 116 | maximumLineCount: 4 | ||
3553 | 117 | text: i18n.tr("Connect your device to any computer and simply drag files to the Music folder or insert removable media with music.") | ||
3554 | 118 | width: parent.width | ||
3555 | 119 | wrapMode: Text.WordWrap | ||
3556 | 120 | } | ||
3557 | 121 | } | ||
3558 | 122 | } | ||
3559 | 123 | } | ||
3560 | 0 | 124 | ||
3561 | === renamed file 'MusicNowPlaying.qml' => 'app/ui/NowPlayingView.qml' | |||
3562 | --- MusicNowPlaying.qml 2015-01-28 02:30:43 +0000 | |||
3563 | +++ app/ui/NowPlayingView.qml 2015-02-10 03:13:44 +0000 | |||
3564 | @@ -22,11 +22,13 @@ | |||
3565 | 22 | import QtQuick.LocalStorage 2.0 | 22 | import QtQuick.LocalStorage 2.0 |
3566 | 23 | import Ubuntu.Components 1.1 | 23 | import Ubuntu.Components 1.1 |
3567 | 24 | import Ubuntu.Thumbnailer 0.1 | 24 | import Ubuntu.Thumbnailer 0.1 |
3573 | 25 | import "common" | 25 | import "../components" |
3574 | 26 | import "common/ListItemActions" | 26 | import "../components/Flickables" |
3575 | 27 | import "common/Themes/Ambiance" | 27 | import "../components/HeadState" |
3576 | 28 | import "meta-database.js" as Library | 28 | import "../components/ListItemActions" |
3577 | 29 | import "playlists.js" as Playlists | 29 | import "../components/Themes/Ambiance" |
3578 | 30 | import "../logic/meta-database.js" as Library | ||
3579 | 31 | import "../logic/playlists.js" as Playlists | ||
3580 | 30 | 32 | ||
3581 | 31 | MusicPage { | 33 | MusicPage { |
3582 | 32 | id: nowPlaying | 34 | id: nowPlaying |
3583 | @@ -35,7 +37,7 @@ | |||
3584 | 35 | title: isListView ? queueTitle : nowPlayingTitle | 37 | title: isListView ? queueTitle : nowPlayingTitle |
3585 | 36 | visible: false | 38 | visible: false |
3586 | 37 | 39 | ||
3588 | 38 | property bool isListView: false | 40 | property alias isListView: nowPlaying.isListView |
3589 | 39 | // TRANSLATORS: this appears in the header with limited space (around 20 characters) | 41 | // TRANSLATORS: this appears in the header with limited space (around 20 characters) |
3590 | 40 | property string nowPlayingTitle: i18n.tr("Now playing") | 42 | property string nowPlayingTitle: i18n.tr("Now playing") |
3591 | 41 | // TRANSLATORS: this appears in the header with limited space (around 20 characters) | 43 | // TRANSLATORS: this appears in the header with limited space (around 20 characters) |
3592 | @@ -98,14 +100,8 @@ | |||
3593 | 98 | 100 | ||
3594 | 99 | items.push(makeDict(trackQueue.model.get(player.currentIndex))); | 101 | items.push(makeDict(trackQueue.model.get(player.currentIndex))); |
3595 | 100 | 102 | ||
3604 | 101 | var comp = Qt.createComponent("MusicaddtoPlaylist.qml") | 103 | mainPageStack.push(Qt.resolvedUrl("AddToPlaylist.qml"), |
3605 | 102 | var addToPlaylist = comp.createObject(mainPageStack, {"chosenElements": items}); | 104 | {"chosenElements": items}) |
3598 | 103 | |||
3599 | 104 | if (addToPlaylist == null) { // Error Handling | ||
3600 | 105 | console.log("Error creating object"); | ||
3601 | 106 | } | ||
3602 | 107 | |||
3603 | 108 | mainPageStack.push(addToPlaylist) | ||
3606 | 109 | } | 105 | } |
3607 | 110 | }, | 106 | }, |
3608 | 111 | Action { | 107 | Action { |
3609 | @@ -126,619 +122,22 @@ | |||
3610 | 126 | actions: defaultState.actions | 122 | actions: defaultState.actions |
3611 | 127 | } | 123 | } |
3612 | 128 | }, | 124 | }, |
3678 | 129 | PageHeadState { | 125 | MultiSelectHeadState { |
3679 | 130 | id: selectionState | 126 | addToQueue: false |
3680 | 131 | 127 | listview: queueListLoader.item | |
3681 | 132 | name: "selection" | 128 | removable: true |
3682 | 133 | backAction: Action { | 129 | thisPage: nowPlaying |
3683 | 134 | text: i18n.tr("Cancel selection") | 130 | |
3684 | 135 | iconName: "back" | 131 | onRemoved: { |
3685 | 136 | onTriggered: { | 132 | // Remove the tracks from the queue |
3686 | 137 | queueListLoader.item.clearSelection() | 133 | // Use slice() to copy the list |
3687 | 138 | queueListLoader.item.state = "normal" | 134 | // so that the indexes don't change as they are removed |
3688 | 139 | } | 135 | trackQueue.removeQueueList(selectedItems.slice()) |
3624 | 140 | } | ||
3625 | 141 | actions: [ | ||
3626 | 142 | Action { | ||
3627 | 143 | text: i18n.tr("Select All") | ||
3628 | 144 | iconName: "select" | ||
3629 | 145 | onTriggered: { | ||
3630 | 146 | if (queueListLoader.item.selectedItems.length === trackQueue.model.count) { | ||
3631 | 147 | queueListLoader.item.clearSelection() | ||
3632 | 148 | } else { | ||
3633 | 149 | queueListLoader.item.selectAll() | ||
3634 | 150 | } | ||
3635 | 151 | } | ||
3636 | 152 | }, | ||
3637 | 153 | Action { | ||
3638 | 154 | enabled: queueListLoader.item.selectedItems.length > 0 | ||
3639 | 155 | iconName: "add-to-playlist" | ||
3640 | 156 | text: i18n.tr("Add to playlist") | ||
3641 | 157 | onTriggered: { | ||
3642 | 158 | var items = [] | ||
3643 | 159 | |||
3644 | 160 | for (var i=0; i < queueListLoader.item.selectedItems.length; i++) { | ||
3645 | 161 | items.push(makeDict(trackQueue.model.get(queueListLoader.item.selectedItems[i]))); | ||
3646 | 162 | } | ||
3647 | 163 | |||
3648 | 164 | var comp = Qt.createComponent("MusicaddtoPlaylist.qml") | ||
3649 | 165 | var addToPlaylist = comp.createObject(mainPageStack, {"chosenElements": items}); | ||
3650 | 166 | |||
3651 | 167 | if (addToPlaylist == null) { // Error Handling | ||
3652 | 168 | console.log("Error creating object"); | ||
3653 | 169 | } | ||
3654 | 170 | |||
3655 | 171 | mainPageStack.push(addToPlaylist) | ||
3656 | 172 | |||
3657 | 173 | queueListLoader.item.closeSelection() | ||
3658 | 174 | } | ||
3659 | 175 | }, | ||
3660 | 176 | Action { | ||
3661 | 177 | enabled: queueListLoader.item.selectedItems.length > 0 | ||
3662 | 178 | iconName: "delete" | ||
3663 | 179 | text: i18n.tr("Delete") | ||
3664 | 180 | onTriggered: { | ||
3665 | 181 | // Remove the tracks from the queue | ||
3666 | 182 | // Use slice() to copy the list | ||
3667 | 183 | // so that the indexes don't change as they are removed | ||
3668 | 184 | trackQueue.removeQueueList(queueListLoader.item.selectedItems.slice()) | ||
3669 | 185 | |||
3670 | 186 | queueListLoader.item.closeSelection() | ||
3671 | 187 | } | ||
3672 | 188 | } | ||
3673 | 189 | ] | ||
3674 | 190 | PropertyChanges { | ||
3675 | 191 | target: nowPlaying.head | ||
3676 | 192 | backAction: selectionState.backAction | ||
3677 | 193 | actions: selectionState.actions | ||
3689 | 194 | } | 136 | } |
3690 | 195 | } | 137 | } |
3691 | 196 | ] | 138 | ] |
3692 | 197 | 139 | ||
4238 | 198 | Item { | 140 | NowPlaying { |
4239 | 199 | id: fullview | 141 | id: view |
3695 | 200 | anchors { | ||
3696 | 201 | top: parent.top | ||
3697 | 202 | topMargin: mainView.header.height | ||
3698 | 203 | } | ||
3699 | 204 | height: parent.height - mainView.header.height - units.gu(9.5) | ||
3700 | 205 | visible: !isListView | ||
3701 | 206 | width: parent.width | ||
3702 | 207 | |||
3703 | 208 | BlurredBackground { | ||
3704 | 209 | id: blurredBackground | ||
3705 | 210 | anchors { | ||
3706 | 211 | left: parent.left | ||
3707 | 212 | right: parent.right | ||
3708 | 213 | top: parent.top | ||
3709 | 214 | } | ||
3710 | 215 | art: albumImage.firstSource | ||
3711 | 216 | height: parent.height - units.gu(7) | ||
3712 | 217 | |||
3713 | 218 | Item { | ||
3714 | 219 | id: albumImageContainer | ||
3715 | 220 | anchors { | ||
3716 | 221 | horizontalCenter: parent.horizontalCenter | ||
3717 | 222 | top: parent.top | ||
3718 | 223 | } | ||
3719 | 224 | height: parent.height | ||
3720 | 225 | width: parent.width | ||
3721 | 226 | |||
3722 | 227 | CoverGrid { | ||
3723 | 228 | id: albumImage | ||
3724 | 229 | anchors.centerIn: parent | ||
3725 | 230 | covers: [{art: player.currentMetaArt, author: player.currentMetaArtist, album: player.currentMetaAlbum}] | ||
3726 | 231 | size: parent.width > parent.height ? parent.height : parent.width | ||
3727 | 232 | } | ||
3728 | 233 | } | ||
3729 | 234 | |||
3730 | 235 | Rectangle { | ||
3731 | 236 | id: nowPlayingWideAspectLabelsBackground | ||
3732 | 237 | anchors.bottom: parent.bottom | ||
3733 | 238 | color: styleMusic.common.black | ||
3734 | 239 | height: nowPlayingWideAspectTitle.lineCount === 1 ? units.gu(10) : units.gu(13) | ||
3735 | 240 | opacity: 0.8 | ||
3736 | 241 | width: parent.width | ||
3737 | 242 | } | ||
3738 | 243 | |||
3739 | 244 | /* Column for labels in wideAspect */ | ||
3740 | 245 | Column { | ||
3741 | 246 | id: nowPlayingWideAspectLabels | ||
3742 | 247 | spacing: units.gu(1) | ||
3743 | 248 | anchors { | ||
3744 | 249 | left: parent.left | ||
3745 | 250 | leftMargin: units.gu(2) | ||
3746 | 251 | right: parent.right | ||
3747 | 252 | rightMargin: units.gu(2) | ||
3748 | 253 | top: nowPlayingWideAspectLabelsBackground.top | ||
3749 | 254 | topMargin: nowPlayingWideAspectTitle.lineCount === 1 ? units.gu(2) : units.gu(1.5) | ||
3750 | 255 | } | ||
3751 | 256 | |||
3752 | 257 | /* Title of track */ | ||
3753 | 258 | Label { | ||
3754 | 259 | id: nowPlayingWideAspectTitle | ||
3755 | 260 | anchors { | ||
3756 | 261 | left: parent.left | ||
3757 | 262 | leftMargin: units.gu(1) | ||
3758 | 263 | right: parent.right | ||
3759 | 264 | rightMargin: units.gu(1) | ||
3760 | 265 | } | ||
3761 | 266 | color: styleMusic.playerControls.labelColor | ||
3762 | 267 | elide: Text.ElideRight | ||
3763 | 268 | fontSize: "x-large" | ||
3764 | 269 | maximumLineCount: 2 | ||
3765 | 270 | objectName: "playercontroltitle" | ||
3766 | 271 | text: trackQueue.model.count === 0 ? "" : player.currentMetaTitle === "" ? player.currentMetaFile : player.currentMetaTitle | ||
3767 | 272 | wrapMode: Text.WordWrap | ||
3768 | 273 | } | ||
3769 | 274 | |||
3770 | 275 | /* Artist of track */ | ||
3771 | 276 | Label { | ||
3772 | 277 | id: nowPlayingWideAspectArtist | ||
3773 | 278 | anchors { | ||
3774 | 279 | left: parent.left | ||
3775 | 280 | leftMargin: units.gu(1) | ||
3776 | 281 | right: parent.right | ||
3777 | 282 | rightMargin: units.gu(1) | ||
3778 | 283 | } | ||
3779 | 284 | color: styleMusic.nowPlaying.labelSecondaryColor | ||
3780 | 285 | elide: Text.ElideRight | ||
3781 | 286 | fontSize: "small" | ||
3782 | 287 | text: trackQueue.model.count === 0 ? "" : player.currentMetaArtist | ||
3783 | 288 | } | ||
3784 | 289 | } | ||
3785 | 290 | |||
3786 | 291 | /* Detect cover art swipe */ | ||
3787 | 292 | MouseArea { | ||
3788 | 293 | anchors.fill: parent | ||
3789 | 294 | property string direction: "None" | ||
3790 | 295 | property real lastX: -1 | ||
3791 | 296 | |||
3792 | 297 | onPressed: lastX = mouse.x | ||
3793 | 298 | |||
3794 | 299 | onReleased: { | ||
3795 | 300 | var diff = mouse.x - lastX | ||
3796 | 301 | if (Math.abs(diff) < units.gu(4)) { | ||
3797 | 302 | return; | ||
3798 | 303 | } else if (diff < 0) { | ||
3799 | 304 | player.nextSong() | ||
3800 | 305 | } else if (diff > 0) { | ||
3801 | 306 | player.previousSong() | ||
3802 | 307 | } | ||
3803 | 308 | } | ||
3804 | 309 | } | ||
3805 | 310 | } | ||
3806 | 311 | |||
3807 | 312 | /* Background for progress bar component */ | ||
3808 | 313 | Rectangle { | ||
3809 | 314 | id: musicToolbarFullProgressBackground | ||
3810 | 315 | anchors { | ||
3811 | 316 | bottom: parent.bottom | ||
3812 | 317 | left: parent.left | ||
3813 | 318 | right: parent.right | ||
3814 | 319 | top: blurredBackground.bottom | ||
3815 | 320 | } | ||
3816 | 321 | color: styleMusic.common.black | ||
3817 | 322 | } | ||
3818 | 323 | |||
3819 | 324 | /* Progress bar component */ | ||
3820 | 325 | Item { | ||
3821 | 326 | id: musicToolbarFullProgressContainer | ||
3822 | 327 | anchors.left: parent.left | ||
3823 | 328 | anchors.leftMargin: units.gu(3) | ||
3824 | 329 | anchors.right: parent.right | ||
3825 | 330 | anchors.rightMargin: units.gu(3) | ||
3826 | 331 | anchors.top: blurredBackground.bottom | ||
3827 | 332 | anchors.topMargin: units.gu(1) | ||
3828 | 333 | height: units.gu(3) | ||
3829 | 334 | width: parent.width | ||
3830 | 335 | |||
3831 | 336 | /* Position label */ | ||
3832 | 337 | Label { | ||
3833 | 338 | id: musicToolbarFullPositionLabel | ||
3834 | 339 | anchors.top: progressSliderMusic.bottom | ||
3835 | 340 | anchors.topMargin: units.gu(-2) | ||
3836 | 341 | anchors.left: parent.left | ||
3837 | 342 | color: styleMusic.nowPlaying.labelSecondaryColor | ||
3838 | 343 | fontSize: "small" | ||
3839 | 344 | height: parent.height | ||
3840 | 345 | horizontalAlignment: Text.AlignHCenter | ||
3841 | 346 | text: durationToString(player.position) | ||
3842 | 347 | verticalAlignment: Text.AlignVCenter | ||
3843 | 348 | width: units.gu(3) | ||
3844 | 349 | } | ||
3845 | 350 | |||
3846 | 351 | Slider { | ||
3847 | 352 | id: progressSliderMusic | ||
3848 | 353 | anchors.left: parent.left | ||
3849 | 354 | anchors.right: parent.right | ||
3850 | 355 | maximumValue: player.duration // load value at startup | ||
3851 | 356 | objectName: "progressSliderShape" | ||
3852 | 357 | style: UbuntuBlueSliderStyle {} | ||
3853 | 358 | value: player.position // load value at startup | ||
3854 | 359 | |||
3855 | 360 | function formatValue(v) { | ||
3856 | 361 | if (seeking) { // update position label while dragging | ||
3857 | 362 | musicToolbarFullPositionLabel.text = durationToString(v) | ||
3858 | 363 | } | ||
3859 | 364 | |||
3860 | 365 | return durationToString(v) | ||
3861 | 366 | } | ||
3862 | 367 | |||
3863 | 368 | property bool seeking: false | ||
3864 | 369 | property bool seeked: false | ||
3865 | 370 | |||
3866 | 371 | onSeekingChanged: { | ||
3867 | 372 | if (seeking === false) { | ||
3868 | 373 | musicToolbarFullPositionLabel.text = durationToString(player.position) | ||
3869 | 374 | } | ||
3870 | 375 | } | ||
3871 | 376 | |||
3872 | 377 | onPressedChanged: { | ||
3873 | 378 | seeking = pressed | ||
3874 | 379 | |||
3875 | 380 | if (!pressed) { | ||
3876 | 381 | seeked = true | ||
3877 | 382 | player.seek(value) | ||
3878 | 383 | |||
3879 | 384 | musicToolbarFullPositionLabel.text = durationToString(value) | ||
3880 | 385 | } | ||
3881 | 386 | } | ||
3882 | 387 | |||
3883 | 388 | Connections { | ||
3884 | 389 | target: player | ||
3885 | 390 | onPositionChanged: { | ||
3886 | 391 | // seeked is a workaround for bug 1310706 as the first position after a seek is sometimes invalid (0) | ||
3887 | 392 | if (progressSliderMusic.seeking === false && !progressSliderMusic.seeked) { | ||
3888 | 393 | musicToolbarFullPositionLabel.text = durationToString(player.position) | ||
3889 | 394 | musicToolbarFullDurationLabel.text = durationToString(player.duration) | ||
3890 | 395 | |||
3891 | 396 | progressSliderMusic.value = player.position | ||
3892 | 397 | progressSliderMusic.maximumValue = player.duration | ||
3893 | 398 | } | ||
3894 | 399 | |||
3895 | 400 | progressSliderMusic.seeked = false; | ||
3896 | 401 | } | ||
3897 | 402 | onStopped: { | ||
3898 | 403 | musicToolbarFullPositionLabel.text = durationToString(0); | ||
3899 | 404 | musicToolbarFullDurationLabel.text = durationToString(0); | ||
3900 | 405 | } | ||
3901 | 406 | } | ||
3902 | 407 | } | ||
3903 | 408 | |||
3904 | 409 | /* Duration label */ | ||
3905 | 410 | Label { | ||
3906 | 411 | id: musicToolbarFullDurationLabel | ||
3907 | 412 | anchors.top: progressSliderMusic.bottom | ||
3908 | 413 | anchors.topMargin: units.gu(-2) | ||
3909 | 414 | anchors.right: parent.right | ||
3910 | 415 | color: styleMusic.nowPlaying.labelSecondaryColor | ||
3911 | 416 | fontSize: "small" | ||
3912 | 417 | height: parent.height | ||
3913 | 418 | horizontalAlignment: Text.AlignHCenter | ||
3914 | 419 | text: durationToString(player.duration) | ||
3915 | 420 | verticalAlignment: Text.AlignVCenter | ||
3916 | 421 | width: units.gu(3) | ||
3917 | 422 | } | ||
3918 | 423 | } | ||
3919 | 424 | } | ||
3920 | 425 | |||
3921 | 426 | Loader { | ||
3922 | 427 | id: queueListLoader | ||
3923 | 428 | anchors { | ||
3924 | 429 | fill: parent | ||
3925 | 430 | } | ||
3926 | 431 | asynchronous: true | ||
3927 | 432 | sourceComponent: ListView { | ||
3928 | 433 | id: queueList | ||
3929 | 434 | anchors { | ||
3930 | 435 | bottomMargin: musicToolbarFullContainer.height + units.gu(2) | ||
3931 | 436 | fill: parent | ||
3932 | 437 | topMargin: units.gu(2) | ||
3933 | 438 | } | ||
3934 | 439 | delegate: queueDelegate | ||
3935 | 440 | footer: Item { | ||
3936 | 441 | height: mainView.height - (styleMusic.common.expandHeight + queueList.currentHeight) + units.gu(8) | ||
3937 | 442 | } | ||
3938 | 443 | model: trackQueue.model | ||
3939 | 444 | objectName: "nowPlayingqueueList" | ||
3940 | 445 | |||
3941 | 446 | property int normalHeight: units.gu(6) | ||
3942 | 447 | property int transitionDuration: 250 // transition length of animations | ||
3943 | 448 | |||
3944 | 449 | onCountChanged: { | ||
3945 | 450 | customdebug("Queue: Now has: " + queueList.count + " tracks") | ||
3946 | 451 | } | ||
3947 | 452 | |||
3948 | 453 | // Requirements for ListItemWithActions | ||
3949 | 454 | property var selectedItems: [] | ||
3950 | 455 | |||
3951 | 456 | signal clearSelection() | ||
3952 | 457 | signal closeSelection() | ||
3953 | 458 | signal selectAll() | ||
3954 | 459 | |||
3955 | 460 | onClearSelection: selectedItems = [] | ||
3956 | 461 | onCloseSelection: { | ||
3957 | 462 | clearSelection() | ||
3958 | 463 | state = "normal" | ||
3959 | 464 | } | ||
3960 | 465 | onSelectAll: { | ||
3961 | 466 | var tmp = selectedItems | ||
3962 | 467 | |||
3963 | 468 | for (var i=0; i < model.count; i++) { | ||
3964 | 469 | if (tmp.indexOf(i) === -1) { | ||
3965 | 470 | tmp.push(i) | ||
3966 | 471 | } | ||
3967 | 472 | } | ||
3968 | 473 | |||
3969 | 474 | selectedItems = tmp | ||
3970 | 475 | } | ||
3971 | 476 | onVisibleChanged: { | ||
3972 | 477 | if (!visible) { | ||
3973 | 478 | closeSelection() | ||
3974 | 479 | } | ||
3975 | 480 | } | ||
3976 | 481 | |||
3977 | 482 | Component.onCompleted: { | ||
3978 | 483 | // FIXME: workaround for qtubuntu not returning values depending on the grid unit definition | ||
3979 | 484 | // for Flickable.maximumFlickVelocity and Flickable.flickDeceleration | ||
3980 | 485 | var scaleFactor = units.gridUnit / 8; | ||
3981 | 486 | maximumFlickVelocity = maximumFlickVelocity * scaleFactor; | ||
3982 | 487 | flickDeceleration = flickDeceleration * scaleFactor; | ||
3983 | 488 | } | ||
3984 | 489 | |||
3985 | 490 | Component { | ||
3986 | 491 | id: queueDelegate | ||
3987 | 492 | ListItemWithActions { | ||
3988 | 493 | id: queueListItem | ||
3989 | 494 | color: player.currentIndex === index ? "#2c2c34" : styleMusic.mainView.backgroundColor | ||
3990 | 495 | height: queueList.normalHeight | ||
3991 | 496 | objectName: "nowPlayingListItem" + index | ||
3992 | 497 | state: "" | ||
3993 | 498 | |||
3994 | 499 | leftSideAction: Remove { | ||
3995 | 500 | onTriggered: trackQueue.removeQueueList([index]) | ||
3996 | 501 | } | ||
3997 | 502 | multiselectable: true | ||
3998 | 503 | reorderable: true | ||
3999 | 504 | rightSideActions: [ | ||
4000 | 505 | AddToPlaylist{ | ||
4001 | 506 | |||
4002 | 507 | } | ||
4003 | 508 | ] | ||
4004 | 509 | |||
4005 | 510 | onItemClicked: { | ||
4006 | 511 | customdebug("File: " + model.filename) // debugger | ||
4007 | 512 | trackQueueClick(index); // toggle track state | ||
4008 | 513 | } | ||
4009 | 514 | onReorder: { | ||
4010 | 515 | console.debug("Move: ", from, to); | ||
4011 | 516 | |||
4012 | 517 | trackQueue.model.move(from, to, 1); | ||
4013 | 518 | Library.moveQueueItem(from, to); | ||
4014 | 519 | |||
4015 | 520 | // Maintain currentIndex with current song | ||
4016 | 521 | if (from === player.currentIndex) { | ||
4017 | 522 | player.currentIndex = to; | ||
4018 | 523 | } | ||
4019 | 524 | else if (from < player.currentIndex && to >= player.currentIndex) { | ||
4020 | 525 | player.currentIndex -= 1; | ||
4021 | 526 | } | ||
4022 | 527 | else if (from > player.currentIndex && to <= player.currentIndex) { | ||
4023 | 528 | player.currentIndex += 1; | ||
4024 | 529 | } | ||
4025 | 530 | |||
4026 | 531 | queueIndex = player.currentIndex | ||
4027 | 532 | } | ||
4028 | 533 | |||
4029 | 534 | Item { | ||
4030 | 535 | id: trackContainer; | ||
4031 | 536 | anchors { | ||
4032 | 537 | fill: parent | ||
4033 | 538 | } | ||
4034 | 539 | |||
4035 | 540 | NumberAnimation { | ||
4036 | 541 | id: trackContainerReorderAnimation | ||
4037 | 542 | target: trackContainer; | ||
4038 | 543 | property: "anchors.leftMargin"; | ||
4039 | 544 | duration: queueList.transitionDuration; | ||
4040 | 545 | to: units.gu(2) | ||
4041 | 546 | } | ||
4042 | 547 | |||
4043 | 548 | NumberAnimation { | ||
4044 | 549 | id: trackContainerResetAnimation | ||
4045 | 550 | target: trackContainer; | ||
4046 | 551 | property: "anchors.leftMargin"; | ||
4047 | 552 | duration: queueList.transitionDuration; | ||
4048 | 553 | to: units.gu(0.5) | ||
4049 | 554 | } | ||
4050 | 555 | |||
4051 | 556 | MusicRow { | ||
4052 | 557 | id: musicRow | ||
4053 | 558 | height: parent.height | ||
4054 | 559 | column: Column { | ||
4055 | 560 | Label { | ||
4056 | 561 | id: trackTitle | ||
4057 | 562 | color: player.currentIndex === index ? UbuntuColors.blue | ||
4058 | 563 | : styleMusic.common.music | ||
4059 | 564 | fontSize: "small" | ||
4060 | 565 | objectName: "titleLabel" | ||
4061 | 566 | text: model.title | ||
4062 | 567 | } | ||
4063 | 568 | |||
4064 | 569 | Label { | ||
4065 | 570 | id: trackArtist | ||
4066 | 571 | color: styleMusic.common.subtitle | ||
4067 | 572 | fontSize: "x-small" | ||
4068 | 573 | objectName: "artistLabel" | ||
4069 | 574 | text: model.author | ||
4070 | 575 | } | ||
4071 | 576 | } | ||
4072 | 577 | } | ||
4073 | 578 | } | ||
4074 | 579 | } | ||
4075 | 580 | } | ||
4076 | 581 | } | ||
4077 | 582 | visible: isListView | ||
4078 | 583 | } | ||
4079 | 584 | |||
4080 | 585 | /* Full toolbar */ | ||
4081 | 586 | Rectangle { | ||
4082 | 587 | id: musicToolbarFullContainer | ||
4083 | 588 | anchors.bottom: parent.bottom | ||
4084 | 589 | color: styleMusic.common.black | ||
4085 | 590 | height: units.gu(10) | ||
4086 | 591 | width: parent.width | ||
4087 | 592 | |||
4088 | 593 | /* Repeat button */ | ||
4089 | 594 | MouseArea { | ||
4090 | 595 | id: nowPlayingRepeatButton | ||
4091 | 596 | anchors.right: nowPlayingPreviousButton.left | ||
4092 | 597 | anchors.rightMargin: units.gu(1) | ||
4093 | 598 | anchors.verticalCenter: nowPlayingPlayButton.verticalCenter | ||
4094 | 599 | height: units.gu(6) | ||
4095 | 600 | opacity: player.repeat && !emptyPage.noMusic ? 1 : .4 | ||
4096 | 601 | width: height | ||
4097 | 602 | onClicked: player.repeat = !player.repeat | ||
4098 | 603 | |||
4099 | 604 | Icon { | ||
4100 | 605 | id: repeatIcon | ||
4101 | 606 | height: units.gu(3) | ||
4102 | 607 | width: height | ||
4103 | 608 | anchors.verticalCenter: parent.verticalCenter | ||
4104 | 609 | anchors.horizontalCenter: parent.horizontalCenter | ||
4105 | 610 | color: "white" | ||
4106 | 611 | name: "media-playlist-repeat" | ||
4107 | 612 | objectName: "repeatShape" | ||
4108 | 613 | opacity: player.repeat && !emptyPage.noMusic ? 1 : .4 | ||
4109 | 614 | } | ||
4110 | 615 | } | ||
4111 | 616 | |||
4112 | 617 | /* Previous button */ | ||
4113 | 618 | MouseArea { | ||
4114 | 619 | id: nowPlayingPreviousButton | ||
4115 | 620 | anchors.right: nowPlayingPlayButton.left | ||
4116 | 621 | anchors.rightMargin: units.gu(1) | ||
4117 | 622 | anchors.verticalCenter: nowPlayingPlayButton.verticalCenter | ||
4118 | 623 | height: units.gu(6) | ||
4119 | 624 | opacity: trackQueue.model.count === 0 ? .4 : 1 | ||
4120 | 625 | width: height | ||
4121 | 626 | onClicked: player.previousSong() | ||
4122 | 627 | |||
4123 | 628 | Icon { | ||
4124 | 629 | id: nowPlayingPreviousIndicator | ||
4125 | 630 | height: units.gu(3) | ||
4126 | 631 | width: height | ||
4127 | 632 | anchors.verticalCenter: parent.verticalCenter | ||
4128 | 633 | anchors.horizontalCenter: parent.horizontalCenter | ||
4129 | 634 | color: "white" | ||
4130 | 635 | name: "media-skip-backward" | ||
4131 | 636 | objectName: "previousShape" | ||
4132 | 637 | opacity: 1 | ||
4133 | 638 | } | ||
4134 | 639 | } | ||
4135 | 640 | |||
4136 | 641 | /* Play/Pause button */ | ||
4137 | 642 | MouseArea { | ||
4138 | 643 | id: nowPlayingPlayButton | ||
4139 | 644 | anchors.centerIn: parent | ||
4140 | 645 | height: units.gu(10) | ||
4141 | 646 | width: height | ||
4142 | 647 | onClicked: player.toggle() | ||
4143 | 648 | |||
4144 | 649 | Icon { | ||
4145 | 650 | id: nowPlayingPlayIndicator | ||
4146 | 651 | height: units.gu(6) | ||
4147 | 652 | width: height | ||
4148 | 653 | anchors.verticalCenter: parent.verticalCenter | ||
4149 | 654 | anchors.horizontalCenter: parent.horizontalCenter | ||
4150 | 655 | opacity: emptyPage.noMusic ? .4 : 1 | ||
4151 | 656 | color: "white" | ||
4152 | 657 | name: player.playbackState === MediaPlayer.PlayingState ? "media-playback-pause" : "media-playback-start" | ||
4153 | 658 | objectName: "playShape" | ||
4154 | 659 | } | ||
4155 | 660 | } | ||
4156 | 661 | |||
4157 | 662 | /* Next button */ | ||
4158 | 663 | MouseArea { | ||
4159 | 664 | id: nowPlayingNextButton | ||
4160 | 665 | anchors.left: nowPlayingPlayButton.right | ||
4161 | 666 | anchors.leftMargin: units.gu(1) | ||
4162 | 667 | anchors.verticalCenter: nowPlayingPlayButton.verticalCenter | ||
4163 | 668 | height: units.gu(6) | ||
4164 | 669 | opacity: trackQueue.model.count === 0 ? .4 : 1 | ||
4165 | 670 | width: height | ||
4166 | 671 | onClicked: player.nextSong() | ||
4167 | 672 | |||
4168 | 673 | Icon { | ||
4169 | 674 | id: nowPlayingNextIndicator | ||
4170 | 675 | height: units.gu(3) | ||
4171 | 676 | width: height | ||
4172 | 677 | anchors.verticalCenter: parent.verticalCenter | ||
4173 | 678 | anchors.horizontalCenter: parent.horizontalCenter | ||
4174 | 679 | color: "white" | ||
4175 | 680 | name: "media-skip-forward" | ||
4176 | 681 | objectName: "forwardShape" | ||
4177 | 682 | opacity: 1 | ||
4178 | 683 | } | ||
4179 | 684 | } | ||
4180 | 685 | |||
4181 | 686 | /* Shuffle button */ | ||
4182 | 687 | MouseArea { | ||
4183 | 688 | id: nowPlayingShuffleButton | ||
4184 | 689 | anchors.left: nowPlayingNextButton.right | ||
4185 | 690 | anchors.leftMargin: units.gu(1) | ||
4186 | 691 | anchors.verticalCenter: nowPlayingPlayButton.verticalCenter | ||
4187 | 692 | height: units.gu(6) | ||
4188 | 693 | opacity: player.shuffle && !emptyPage.noMusic ? 1 : .4 | ||
4189 | 694 | width: height | ||
4190 | 695 | onClicked: player.shuffle = !player.shuffle | ||
4191 | 696 | |||
4192 | 697 | Icon { | ||
4193 | 698 | id: shuffleIcon | ||
4194 | 699 | height: units.gu(3) | ||
4195 | 700 | width: height | ||
4196 | 701 | anchors.verticalCenter: parent.verticalCenter | ||
4197 | 702 | anchors.horizontalCenter: parent.horizontalCenter | ||
4198 | 703 | color: "white" | ||
4199 | 704 | name: "media-playlist-shuffle" | ||
4200 | 705 | objectName: "shuffleShape" | ||
4201 | 706 | opacity: player.shuffle && !emptyPage.noMusic ? 1 : .4 | ||
4202 | 707 | } | ||
4203 | 708 | } | ||
4204 | 709 | |||
4205 | 710 | /* Object which provides the progress bar when in the queue */ | ||
4206 | 711 | Rectangle { | ||
4207 | 712 | id: playerControlsProgressBar | ||
4208 | 713 | anchors { | ||
4209 | 714 | bottom: parent.bottom | ||
4210 | 715 | left: parent.left | ||
4211 | 716 | right: parent.right | ||
4212 | 717 | } | ||
4213 | 718 | color: styleMusic.common.black | ||
4214 | 719 | height: units.gu(0.25) | ||
4215 | 720 | visible: isListView | ||
4216 | 721 | |||
4217 | 722 | Rectangle { | ||
4218 | 723 | id: playerControlsProgressBarHint | ||
4219 | 724 | anchors { | ||
4220 | 725 | left: parent.left | ||
4221 | 726 | bottom: parent.bottom | ||
4222 | 727 | } | ||
4223 | 728 | color: UbuntuColors.blue | ||
4224 | 729 | height: parent.height | ||
4225 | 730 | width: player.duration > 0 ? (player.position / player.duration) * playerControlsProgressBar.width : 0 | ||
4226 | 731 | |||
4227 | 732 | Connections { | ||
4228 | 733 | target: player | ||
4229 | 734 | onPositionChanged: { | ||
4230 | 735 | playerControlsProgressBarHint.width = (player.position / player.duration) * playerControlsProgressBar.width | ||
4231 | 736 | } | ||
4232 | 737 | onStopped: { | ||
4233 | 738 | playerControlsProgressBarHint.width = 0; | ||
4234 | 739 | } | ||
4235 | 740 | } | ||
4236 | 741 | } | ||
4237 | 742 | } | ||
4240 | 743 | } | 142 | } |
4241 | 744 | } | 143 | } |
4242 | 745 | 144 | ||
4243 | === renamed file 'MusicPlaylists.qml' => 'app/ui/Playlists.qml' | |||
4244 | --- MusicPlaylists.qml 2015-01-21 00:10:33 +0000 | |||
4245 | +++ app/ui/Playlists.qml 2015-02-10 03:13:44 +0000 | |||
4246 | @@ -23,8 +23,10 @@ | |||
4247 | 23 | import Ubuntu.Components.Popups 1.0 | 23 | import Ubuntu.Components.Popups 1.0 |
4248 | 24 | import QtMultimedia 5.0 | 24 | import QtMultimedia 5.0 |
4249 | 25 | import QtQuick.LocalStorage 2.0 | 25 | import QtQuick.LocalStorage 2.0 |
4252 | 26 | import "playlists.js" as Playlists | 26 | import "../logic/playlists.js" as Playlists |
4253 | 27 | import "common" | 27 | import "../components" |
4254 | 28 | import "../components/Flickables" | ||
4255 | 29 | import "../components/HeadState" | ||
4256 | 28 | 30 | ||
4257 | 29 | // page for the playlists | 31 | // page for the playlists |
4258 | 30 | MusicPage { | 32 | MusicPage { |
4259 | @@ -37,25 +39,10 @@ | |||
4260 | 37 | searchResultsCount: playlistModelFilter.count | 39 | searchResultsCount: playlistModelFilter.count |
4261 | 38 | state: "default" | 40 | state: "default" |
4262 | 39 | states: [ | 41 | states: [ |
4282 | 40 | PageHeadState { | 42 | PlaylistsHeadState { |
4283 | 41 | name: "default" | 43 | newPlaylistEnabled: allSongsModel.count > 0 |
4284 | 42 | head: playlistsPage.head | 44 | searchEnabled: playlistModel.model.count > 0 && allSongsModel.count > 0 |
4285 | 43 | actions: [ | 45 | thisPage: playlistsPage |
4267 | 44 | Action { | ||
4268 | 45 | enabled: allSongsModel.count > 0 | ||
4269 | 46 | objectName: "newPlaylistButton" | ||
4270 | 47 | iconName: "add" | ||
4271 | 48 | onTriggered: { | ||
4272 | 49 | customdebug("New playlist.") | ||
4273 | 50 | PopupUtils.open(newPlaylistDialog, mainView) | ||
4274 | 51 | } | ||
4275 | 52 | }, | ||
4276 | 53 | Action { | ||
4277 | 54 | enabled: playlistModel.model.count > 0 && allSongsModel.count > 0 | ||
4278 | 55 | iconName: "search" | ||
4279 | 56 | onTriggered: playlistsPage.state = "search" | ||
4280 | 57 | } | ||
4281 | 58 | ] | ||
4286 | 59 | }, | 46 | }, |
4287 | 60 | SearchHeadState { | 47 | SearchHeadState { |
4288 | 61 | id: searchHeader | 48 | id: searchHeader |
4289 | @@ -99,25 +86,30 @@ | |||
4290 | 99 | onClicked: { | 86 | onClicked: { |
4291 | 100 | albumTracksModel.filterPlaylistTracks(model.name) | 87 | albumTracksModel.filterPlaylistTracks(model.name) |
4292 | 101 | 88 | ||
4311 | 102 | var comp = Qt.createComponent("common/SongsPage.qml") | 89 | mainPageStack.push(Qt.resolvedUrl("SongsView.qml"), |
4312 | 103 | var songsPage = comp.createObject(mainPageStack, | 90 | { |
4313 | 104 | { | 91 | "album": undefined, |
4314 | 105 | "album": undefined, | 92 | "covers": coverSources, |
4315 | 106 | "covers": coverSources, | 93 | "isAlbum": false, |
4316 | 107 | "isAlbum": false, | 94 | "genre": undefined, |
4317 | 108 | "genre": undefined, | 95 | "page": playlistsPage, |
4318 | 109 | "page": playlistsPage, | 96 | "title": i18n.tr("Playlist"), |
4319 | 110 | "title": i18n.tr("Playlist"), | 97 | "line1": i18n.tr("Playlist"), |
4320 | 111 | "line1": i18n.tr("Playlist"), | 98 | "line2": model.name, |
4321 | 112 | "line2": model.name, | 99 | }) |
4304 | 113 | }); | ||
4305 | 114 | |||
4306 | 115 | if (songsPage == null) { // Error Handling | ||
4307 | 116 | console.log("Error creating object"); | ||
4308 | 117 | } | ||
4309 | 118 | |||
4310 | 119 | mainPageStack.push(songsPage) | ||
4322 | 120 | } | 100 | } |
4323 | 121 | } | 101 | } |
4324 | 122 | } | 102 | } |
4325 | 103 | |||
4326 | 104 | // Overlay to show when no playlists are on the device | ||
4327 | 105 | Loader { | ||
4328 | 106 | anchors { | ||
4329 | 107 | fill: parent | ||
4330 | 108 | topMargin: -playlistsPage.header.height | ||
4331 | 109 | } | ||
4332 | 110 | active: playlistModel.model.count === 0 && playlistModel.workerComplete | ||
4333 | 111 | asynchronous: true | ||
4334 | 112 | source: "../components/PlaylistsEmptyState.qml" | ||
4335 | 113 | visible: active | ||
4336 | 114 | } | ||
4337 | 123 | } | 115 | } |
4338 | 124 | 116 | ||
4339 | === renamed file 'MusicStart.qml' => 'app/ui/Recent.qml' | |||
4340 | --- MusicStart.qml 2014-11-10 22:20:24 +0000 | |||
4341 | +++ app/ui/Recent.qml 2015-02-10 03:13:44 +0000 | |||
4342 | @@ -25,12 +25,14 @@ | |||
4343 | 25 | import Ubuntu.Thumbnailer 0.1 | 25 | import Ubuntu.Thumbnailer 0.1 |
4344 | 26 | import QtMultimedia 5.0 | 26 | import QtMultimedia 5.0 |
4345 | 27 | import QtQuick.LocalStorage 2.0 | 27 | import QtQuick.LocalStorage 2.0 |
4349 | 28 | import "meta-database.js" as Library | 28 | import "../logic/meta-database.js" as Library |
4350 | 29 | import "playlists.js" as Playlists | 29 | import "../logic/playlists.js" as Playlists |
4351 | 30 | import "common" | 30 | import "../components" |
4352 | 31 | import "../components/Flickables" | ||
4353 | 31 | 32 | ||
4354 | 32 | MusicPage { | 33 | MusicPage { |
4356 | 33 | id: mainpage | 34 | id: recentPage |
4357 | 35 | objectName: "recentPage" | ||
4358 | 34 | title: i18n.tr("Recent") | 36 | title: i18n.tr("Recent") |
4359 | 35 | 37 | ||
4360 | 36 | property bool changed: false | 38 | property bool changed: false |
4361 | @@ -83,25 +85,18 @@ | |||
4362 | 83 | albumTracksModel.filterPlaylistTracks(model.data) | 85 | albumTracksModel.filterPlaylistTracks(model.data) |
4363 | 84 | } | 86 | } |
4364 | 85 | 87 | ||
4384 | 86 | var comp = Qt.createComponent("common/SongsPage.qml") | 88 | mainPageStack.push(Qt.resolvedUrl("SongsView.qml"), |
4385 | 87 | var songsPage = comp.createObject(mainPageStack, | 89 | { |
4386 | 88 | { | 90 | "album": model.type !== "playlist" ? model.data : undefined, |
4387 | 89 | "album": model.type !== "playlist" ? model.data : undefined, | 91 | "artist": model.type !== "playlist" ? recentAlbumSongs.get(0, SongsModel.RoleModelData).artist : undefined, |
4388 | 90 | "artist": model.type !== "playlist" ? recentAlbumSongs.get(0, SongsModel.RoleModelData).artist : undefined, | 92 | "covers": coverSources, |
4389 | 91 | "covers": coverSources, | 93 | "isAlbum": (model.type === "album"), |
4390 | 92 | "isAlbum": (model.type === "album"), | 94 | "genre": undefined, |
4391 | 93 | "genre": undefined, | 95 | "page": recentPage, |
4392 | 94 | "page": mainpage, | 96 | "title": (model.type === "album") ? i18n.tr("Album") : i18n.tr("Playlist"), |
4393 | 95 | "title": (model.type === "album") ? i18n.tr("Album") : i18n.tr("Playlist"), | 97 | "line1": secondaryText, |
4394 | 96 | "line1": secondaryText, | 98 | "line2": primaryText, |
4395 | 97 | "line2": primaryText, | 99 | }) |
4377 | 98 | }); | ||
4378 | 99 | |||
4379 | 100 | if (songsPage == null) { // Error Handling | ||
4380 | 101 | console.log("Error creating object"); | ||
4381 | 102 | } | ||
4382 | 103 | |||
4383 | 104 | mainPageStack.push(songsPage) | ||
4396 | 105 | } | 100 | } |
4397 | 106 | } | 101 | } |
4398 | 107 | } | 102 | } |
4399 | 108 | 103 | ||
4400 | === renamed file 'MusicTracks.qml' => 'app/ui/Songs.qml' | |||
4401 | --- MusicTracks.qml 2015-01-26 03:20:37 +0000 | |||
4402 | +++ app/ui/Songs.qml 2015-02-10 03:13:44 +0000 | |||
4403 | @@ -23,99 +23,41 @@ | |||
4404 | 23 | import Ubuntu.Thumbnailer 0.1 | 23 | import Ubuntu.Thumbnailer 0.1 |
4405 | 24 | import QtMultimedia 5.0 | 24 | import QtMultimedia 5.0 |
4406 | 25 | import QtQuick.LocalStorage 2.0 | 25 | import QtQuick.LocalStorage 2.0 |
4410 | 26 | import "playlists.js" as Playlists | 26 | import "../logic/playlists.js" as Playlists |
4411 | 27 | import "common" | 27 | import "../components" |
4412 | 28 | import "common/ListItemActions" | 28 | import "../components/Flickables" |
4413 | 29 | import "../components/HeadState" | ||
4414 | 30 | import "../components/ListItemActions" | ||
4415 | 29 | 31 | ||
4416 | 30 | 32 | ||
4417 | 31 | MusicPage { | 33 | MusicPage { |
4420 | 32 | id: tracksPage | 34 | id: songsPage |
4421 | 33 | objectName: "tracksPage" | 35 | objectName: "songsPage" |
4422 | 34 | title: i18n.tr("Songs") | 36 | title: i18n.tr("Songs") |
4423 | 35 | searchable: true | 37 | searchable: true |
4424 | 36 | searchResultsCount: songsModelFilter.count | 38 | searchResultsCount: songsModelFilter.count |
4425 | 37 | state: "default" | 39 | state: "default" |
4426 | 38 | states: [ | 40 | states: [ |
4434 | 39 | PageHeadState { | 41 | SearchableHeadState { |
4435 | 40 | name: "default" | 42 | thisPage: songsPage |
4436 | 41 | head: tracksPage.head | 43 | searchEnabled: songsModelFilter.count > 0 |
4430 | 42 | actions: Action { | ||
4431 | 43 | iconName: "search" | ||
4432 | 44 | onTriggered: tracksPage.state = "search" | ||
4433 | 45 | } | ||
4437 | 46 | }, | 44 | }, |
4502 | 47 | PageHeadState { | 45 | MultiSelectHeadState { |
4503 | 48 | id: selectionState | 46 | listview: tracklist |
4504 | 49 | name: "selection" | 47 | thisPage: songsPage |
4441 | 50 | backAction: Action { | ||
4442 | 51 | text: i18n.tr("Cancel selection") | ||
4443 | 52 | iconName: "back" | ||
4444 | 53 | onTriggered: { | ||
4445 | 54 | tracklist.clearSelection() | ||
4446 | 55 | tracklist.state = "normal" | ||
4447 | 56 | } | ||
4448 | 57 | } | ||
4449 | 58 | head: tracksPage.head | ||
4450 | 59 | actions: [ | ||
4451 | 60 | Action { | ||
4452 | 61 | iconName: "select" | ||
4453 | 62 | text: i18n.tr("Select All") | ||
4454 | 63 | onTriggered: { | ||
4455 | 64 | if (tracklist.selectedItems.length === tracklist.model.count) { | ||
4456 | 65 | tracklist.clearSelection() | ||
4457 | 66 | } else { | ||
4458 | 67 | tracklist.selectAll() | ||
4459 | 68 | } | ||
4460 | 69 | } | ||
4461 | 70 | }, | ||
4462 | 71 | Action { | ||
4463 | 72 | enabled: tracklist.selectedItems.length !== 0 | ||
4464 | 73 | iconName: "add-to-playlist" | ||
4465 | 74 | text: i18n.tr("Add to playlist") | ||
4466 | 75 | onTriggered: { | ||
4467 | 76 | var items = [] | ||
4468 | 77 | |||
4469 | 78 | for (var i=0; i < tracklist.selectedItems.length; i++) { | ||
4470 | 79 | items.push(makeDict(tracklist.model.get(tracklist.selectedItems[i], tracklist.model.RoleModelData))); | ||
4471 | 80 | } | ||
4472 | 81 | |||
4473 | 82 | var comp = Qt.createComponent("MusicaddtoPlaylist.qml") | ||
4474 | 83 | var addToPlaylist = comp.createObject(mainPageStack, {"chosenElements": items}); | ||
4475 | 84 | |||
4476 | 85 | if (addToPlaylist == null) { // Error Handling | ||
4477 | 86 | console.log("Error creating object"); | ||
4478 | 87 | } | ||
4479 | 88 | |||
4480 | 89 | mainPageStack.push(addToPlaylist) | ||
4481 | 90 | |||
4482 | 91 | tracklist.closeSelection() | ||
4483 | 92 | } | ||
4484 | 93 | }, | ||
4485 | 94 | Action { | ||
4486 | 95 | enabled: tracklist.selectedItems.length > 0 | ||
4487 | 96 | iconName: "add" | ||
4488 | 97 | text: i18n.tr("Add to queue") | ||
4489 | 98 | onTriggered: { | ||
4490 | 99 | var items = [] | ||
4491 | 100 | |||
4492 | 101 | for (var i=0; i < tracklist.selectedItems.length; i++) { | ||
4493 | 102 | items.push(tracklist.model.get(tracklist.selectedItems[i], tracklist.model.RoleModelData)); | ||
4494 | 103 | } | ||
4495 | 104 | |||
4496 | 105 | trackQueue.appendList(items) | ||
4497 | 106 | |||
4498 | 107 | tracklist.closeSelection() | ||
4499 | 108 | } | ||
4500 | 109 | } | ||
4501 | 110 | ] | ||
4505 | 111 | }, | 48 | }, |
4506 | 112 | SearchHeadState { | 49 | SearchHeadState { |
4507 | 113 | id: searchHeader | 50 | id: searchHeader |
4509 | 114 | thisPage: tracksPage | 51 | thisPage: songsPage |
4510 | 115 | } | 52 | } |
4511 | 116 | ] | 53 | ] |
4512 | 117 | 54 | ||
4514 | 118 | ListView { | 55 | // Hack for autopilot otherwise Albums appears as MusicPage |
4515 | 56 | // due to bug 1341671 it is required that there is a property so that | ||
4516 | 57 | // qml doesn't optimise using the parent type | ||
4517 | 58 | property bool bug1341671workaround: true | ||
4518 | 59 | |||
4519 | 60 | MultiSelectListView { | ||
4520 | 119 | id: tracklist | 61 | id: tracklist |
4521 | 120 | anchors { | 62 | anchors { |
4522 | 121 | bottomMargin: units.gu(2) | 63 | bottomMargin: units.gu(2) |
4523 | @@ -139,49 +81,12 @@ | |||
4524 | 139 | filterCaseSensitivity: Qt.CaseInsensitive | 81 | filterCaseSensitivity: Qt.CaseInsensitive |
4525 | 140 | } | 82 | } |
4526 | 141 | 83 | ||
4527 | 142 | Component.onCompleted: { | ||
4528 | 143 | // FIXME: workaround for qtubuntu not returning values depending on the grid unit definition | ||
4529 | 144 | // for Flickable.maximumFlickVelocity and Flickable.flickDeceleration | ||
4530 | 145 | var scaleFactor = units.gridUnit / 8; | ||
4531 | 146 | maximumFlickVelocity = maximumFlickVelocity * scaleFactor; | ||
4532 | 147 | flickDeceleration = flickDeceleration * scaleFactor; | ||
4533 | 148 | } | ||
4534 | 149 | |||
4535 | 150 | // Requirements for ListItemWithActions | ||
4536 | 151 | property var selectedItems: [] | ||
4537 | 152 | |||
4538 | 153 | signal clearSelection() | ||
4539 | 154 | signal closeSelection() | ||
4540 | 155 | signal selectAll() | ||
4541 | 156 | |||
4542 | 157 | onClearSelection: selectedItems = [] | ||
4543 | 158 | onCloseSelection: { | ||
4544 | 159 | clearSelection() | ||
4545 | 160 | state = "normal" | ||
4546 | 161 | } | ||
4547 | 162 | onStateChanged: { | 84 | onStateChanged: { |
4548 | 163 | if (state === "multiselectable") { | 85 | if (state === "multiselectable") { |
4550 | 164 | tracksPage.state = "selection" | 86 | songsPage.state = "selection" |
4551 | 165 | } else { | 87 | } else { |
4552 | 166 | searchHeader.query = "" // force query back to default | 88 | searchHeader.query = "" // force query back to default |
4571 | 167 | tracksPage.state = "default" | 89 | songsPage.state = "default" |
4554 | 168 | } | ||
4555 | 169 | } | ||
4556 | 170 | |||
4557 | 171 | onSelectAll: { | ||
4558 | 172 | var tmp = selectedItems | ||
4559 | 173 | |||
4560 | 174 | for (var i=0; i < model.count; i++) { | ||
4561 | 175 | if (tmp.indexOf(i) === -1) { | ||
4562 | 176 | tmp.push(i) | ||
4563 | 177 | } | ||
4564 | 178 | } | ||
4565 | 179 | |||
4566 | 180 | selectedItems = tmp | ||
4567 | 181 | } | ||
4568 | 182 | onVisibleChanged: { | ||
4569 | 183 | if (!visible) { | ||
4570 | 184 | closeSelection() | ||
4572 | 185 | } | 90 | } |
4573 | 186 | } | 91 | } |
4574 | 187 | 92 | ||
4575 | @@ -204,7 +109,7 @@ | |||
4576 | 204 | ] | 109 | ] |
4577 | 205 | 110 | ||
4578 | 206 | onItemClicked: { | 111 | onItemClicked: { |
4580 | 207 | if (tracksPage.state === "search") { // only play single track when searching | 112 | if (songsPage.state === "search") { // only play single track when searching |
4581 | 208 | trackQueue.clear() | 113 | trackQueue.clear() |
4582 | 209 | trackQueue.append(songsModelFilter.get(index)) | 114 | trackQueue.append(songsModelFilter.get(index)) |
4583 | 210 | trackQueueClick(0) | 115 | trackQueueClick(0) |
4584 | 211 | 116 | ||
4585 | === renamed file 'common/SongsPage.qml' => 'app/ui/SongsView.qml' | |||
4586 | --- common/SongsPage.qml 2015-01-30 01:23:39 +0000 | |||
4587 | +++ app/ui/SongsView.qml 2015-02-10 03:13:44 +0000 | |||
4588 | @@ -24,9 +24,13 @@ | |||
4589 | 24 | import Ubuntu.MediaScanner 0.1 | 24 | import Ubuntu.MediaScanner 0.1 |
4590 | 25 | import Ubuntu.Thumbnailer 0.1 | 25 | import Ubuntu.Thumbnailer 0.1 |
4591 | 26 | import QtQuick.LocalStorage 2.0 | 26 | import QtQuick.LocalStorage 2.0 |
4595 | 27 | import "../meta-database.js" as Library | 27 | import "../logic/meta-database.js" as Library |
4596 | 28 | import "../playlists.js" as Playlists | 28 | import "../logic/playlists.js" as Playlists |
4597 | 29 | import "ListItemActions" | 29 | import "../components" |
4598 | 30 | import "../components/Flickables" | ||
4599 | 31 | import "../components/HeadState" | ||
4600 | 32 | import "../components/ListItemActions" | ||
4601 | 33 | import "../components/ViewButton" | ||
4602 | 30 | 34 | ||
4603 | 31 | MusicPage { | 35 | MusicPage { |
4604 | 32 | id: songStackPage | 36 | id: songStackPage |
4605 | @@ -121,7 +125,7 @@ | |||
4606 | 121 | objectName: "editPlaylist" | 125 | objectName: "editPlaylist" |
4607 | 122 | iconName: "edit" | 126 | iconName: "edit" |
4608 | 123 | onTriggered: { | 127 | onTriggered: { |
4610 | 124 | var dialog = PopupUtils.open(editPlaylistDialog, mainView) | 128 | var dialog = PopupUtils.open(Qt.resolvedUrl("../components/Dialog/EditPlaylistDialog.qml"), mainView) |
4611 | 125 | dialog.oldPlaylistName = line2 | 129 | dialog.oldPlaylistName = line2 |
4612 | 126 | } | 130 | } |
4613 | 127 | }, | 131 | }, |
4614 | @@ -129,7 +133,7 @@ | |||
4615 | 129 | objectName: "deletePlaylist" | 133 | objectName: "deletePlaylist" |
4616 | 130 | iconName: "delete" | 134 | iconName: "delete" |
4617 | 131 | onTriggered: { | 135 | onTriggered: { |
4619 | 132 | var dialog = PopupUtils.open(removePlaylistDialog, mainView) | 136 | var dialog = PopupUtils.open(Qt.resolvedUrl("../components/Dialog/RemovePlaylistDialog.qml"), mainView) |
4620 | 133 | dialog.oldPlaylistName = line2 | 137 | dialog.oldPlaylistName = line2 |
4621 | 134 | } | 138 | } |
4622 | 135 | } | 139 | } |
4623 | @@ -140,100 +144,29 @@ | |||
4624 | 140 | actions: playlistState.actions | 144 | actions: playlistState.actions |
4625 | 141 | } | 145 | } |
4626 | 142 | }, | 146 | }, |
4721 | 143 | PageHeadState { | 147 | MultiSelectHeadState { |
4722 | 144 | id: selectionState | 148 | listview: albumtrackslist |
4723 | 145 | name: "selection" | 149 | removable: songStackPage.line1 === i18n.tr("Playlist") |
4724 | 146 | backAction: Action { | 150 | thisPage: songStackPage |
4725 | 147 | text: i18n.tr("Cancel selection") | 151 | |
4726 | 148 | iconName: "back" | 152 | onRemoved: { |
4727 | 149 | onTriggered: { | 153 | for (var i=0; i < selectedItems.length; i++) { |
4728 | 150 | albumtrackslist.clearSelection() | 154 | Playlists.removeFromPlaylist(songStackPage.line2, selectedItems[i]) |
4729 | 151 | albumtrackslist.state = "normal" | 155 | |
4730 | 152 | } | 156 | // Update indexes as an index has been removed |
4731 | 153 | } | 157 | for (var j=i + 1; j < selectedItems.length; j++) { |
4732 | 154 | actions: [ | 158 | if (selectedItems[j] > selectedItems[i]) { |
4733 | 155 | Action { | 159 | selectedItems[j]--; |
4734 | 156 | iconName: "select" | 160 | } |
4735 | 157 | text: i18n.tr("Select All") | 161 | } |
4736 | 158 | onTriggered: { | 162 | } |
4737 | 159 | if (albumtrackslist.selectedItems.length === albumtrackslist.model.count) { | 163 | |
4738 | 160 | albumtrackslist.clearSelection() | 164 | playlistChangedHelper() // update recent/playlist models |
4739 | 161 | } else { | 165 | |
4740 | 162 | albumtrackslist.selectAll() | 166 | albumTracksModel.filterPlaylistTracks(songStackPage.line2) |
4741 | 163 | } | 167 | |
4742 | 164 | } | 168 | // refresh cover art |
4743 | 165 | }, | 169 | songStackPage.covers = Playlists.getPlaylistCovers(songStackPage.line2) |
4650 | 166 | Action { | ||
4651 | 167 | enabled: albumtrackslist.selectedItems.length > 0 | ||
4652 | 168 | iconName: "add-to-playlist" | ||
4653 | 169 | text: i18n.tr("Add to playlist") | ||
4654 | 170 | onTriggered: { | ||
4655 | 171 | var items = [] | ||
4656 | 172 | |||
4657 | 173 | for (var i=0; i < albumtrackslist.selectedItems.length; i++) { | ||
4658 | 174 | items.push(makeDict(albumtrackslist.model.get(albumtrackslist.selectedItems[i], albumtrackslist.model.RoleModelData))); | ||
4659 | 175 | } | ||
4660 | 176 | |||
4661 | 177 | var comp = Qt.createComponent("../MusicaddtoPlaylist.qml") | ||
4662 | 178 | var addToPlaylist = comp.createObject(mainPageStack, {"chosenElements": items, "page": songStackPage}); | ||
4663 | 179 | |||
4664 | 180 | if (addToPlaylist == null) { // Error Handling | ||
4665 | 181 | console.log("Error creating object"); | ||
4666 | 182 | } | ||
4667 | 183 | |||
4668 | 184 | mainPageStack.push(addToPlaylist) | ||
4669 | 185 | |||
4670 | 186 | albumtrackslist.closeSelection() | ||
4671 | 187 | } | ||
4672 | 188 | }, | ||
4673 | 189 | Action { | ||
4674 | 190 | enabled: albumtrackslist.selectedItems.length > 0 | ||
4675 | 191 | iconName: "add" | ||
4676 | 192 | text: i18n.tr("Add to queue") | ||
4677 | 193 | onTriggered: { | ||
4678 | 194 | var items = [] | ||
4679 | 195 | |||
4680 | 196 | for (var i=0; i < albumtrackslist.selectedItems.length; i++) { | ||
4681 | 197 | items.push(albumtrackslist.model.get(albumtrackslist.selectedItems[i], albumtrackslist.model.RoleModelData)); | ||
4682 | 198 | } | ||
4683 | 199 | |||
4684 | 200 | trackQueue.appendList(items) | ||
4685 | 201 | |||
4686 | 202 | albumtrackslist.closeSelection() | ||
4687 | 203 | } | ||
4688 | 204 | }, | ||
4689 | 205 | Action { | ||
4690 | 206 | enabled: albumtrackslist.selectedItems.length > 0 | ||
4691 | 207 | iconName: "delete" | ||
4692 | 208 | text: i18n.tr("Delete") | ||
4693 | 209 | visible: songStackPage.line1 === i18n.tr("Playlist") | ||
4694 | 210 | onTriggered: { | ||
4695 | 211 | for (var i=0; i < albumtrackslist.selectedItems.length; i++) { | ||
4696 | 212 | Playlists.removeFromPlaylist(songStackPage.line2, albumtrackslist.selectedItems[i]) | ||
4697 | 213 | |||
4698 | 214 | // Update indexes as an index has been removed | ||
4699 | 215 | for (var j=i + 1; j < albumtrackslist.selectedItems.length; j++) { | ||
4700 | 216 | if (albumtrackslist.selectedItems[j] > albumtrackslist.selectedItems[i]) { | ||
4701 | 217 | albumtrackslist.selectedItems[j]--; | ||
4702 | 218 | } | ||
4703 | 219 | } | ||
4704 | 220 | } | ||
4705 | 221 | |||
4706 | 222 | albumtrackslist.closeSelection() | ||
4707 | 223 | |||
4708 | 224 | playlistChangedHelper() // update recent/playlist models | ||
4709 | 225 | |||
4710 | 226 | albumTracksModel.filterPlaylistTracks(songStackPage.line2) | ||
4711 | 227 | |||
4712 | 228 | // refresh cover art | ||
4713 | 229 | songStackPage.covers = Playlists.getPlaylistCovers(songStackPage.line2) | ||
4714 | 230 | } | ||
4715 | 231 | } | ||
4716 | 232 | ] | ||
4717 | 233 | PropertyChanges { | ||
4718 | 234 | target: songStackPage.head | ||
4719 | 235 | backAction: selectionState.backAction | ||
4720 | 236 | actions: selectionState.actions | ||
4744 | 237 | } | 170 | } |
4745 | 238 | } | 171 | } |
4746 | 239 | ] | 172 | ] |
4747 | @@ -243,12 +176,12 @@ | |||
4748 | 243 | store: musicStore | 176 | store: musicStore |
4749 | 244 | onStatusChanged: { | 177 | onStatusChanged: { |
4750 | 245 | if (songsModel.status === SongsModel.Ready && loaded && songsModel.count === 0) { | 178 | if (songsModel.status === SongsModel.Ready && loaded && songsModel.count === 0) { |
4752 | 246 | musicToolbar.popPage(songStackPage) | 179 | mainPageStack.popPage(songStackPage) |
4753 | 247 | } | 180 | } |
4754 | 248 | } | 181 | } |
4755 | 249 | } | 182 | } |
4756 | 250 | 183 | ||
4758 | 251 | ListView { | 184 | MultiSelectListView { |
4759 | 252 | id: albumtrackslist | 185 | id: albumtrackslist |
4760 | 253 | anchors { | 186 | anchors { |
4761 | 254 | fill: parent | 187 | fill: parent |
4762 | @@ -258,67 +191,12 @@ | |||
4763 | 258 | objectName: "songspage-listview" | 191 | objectName: "songspage-listview" |
4764 | 259 | width: parent.width | 192 | width: parent.width |
4765 | 260 | 193 | ||
4766 | 261 | // Requirements for ListItemWithActions | ||
4767 | 262 | property var selectedItems: [] | ||
4768 | 263 | |||
4769 | 264 | signal clearSelection() | ||
4770 | 265 | signal closeSelection() | ||
4771 | 266 | signal selectAll() | ||
4772 | 267 | |||
4773 | 268 | onClearSelection: selectedItems = [] | ||
4774 | 269 | onCloseSelection: { | ||
4775 | 270 | clearSelection() | ||
4776 | 271 | state = "normal" | ||
4777 | 272 | } | ||
4778 | 273 | onSelectAll: { | ||
4779 | 274 | var tmp = selectedItems | ||
4780 | 275 | |||
4781 | 276 | for (var i=0; i < model.count; i++) { | ||
4782 | 277 | if (tmp.indexOf(i) === -1) { | ||
4783 | 278 | tmp.push(i) | ||
4784 | 279 | } | ||
4785 | 280 | } | ||
4786 | 281 | |||
4787 | 282 | selectedItems = tmp | ||
4788 | 283 | } | ||
4789 | 284 | onVisibleChanged: { | ||
4790 | 285 | if (!visible) { | ||
4791 | 286 | closeSelection() | ||
4792 | 287 | } | ||
4793 | 288 | } | ||
4794 | 289 | |||
4795 | 290 | Component.onCompleted: { | ||
4796 | 291 | // FIXME: workaround for qtubuntu not returning values depending on the grid unit definition | ||
4797 | 292 | // for Flickable.maximumFlickVelocity and Flickable.flickDeceleration | ||
4798 | 293 | var scaleFactor = units.gridUnit / 8; | ||
4799 | 294 | maximumFlickVelocity = maximumFlickVelocity * scaleFactor; | ||
4800 | 295 | flickDeceleration = flickDeceleration * scaleFactor; | ||
4801 | 296 | } | ||
4802 | 297 | |||
4803 | 298 | header: BlurredHeader { | 194 | header: BlurredHeader { |
4804 | 299 | rightColumn: Column { | 195 | rightColumn: Column { |
4805 | 300 | spacing: units.gu(2) | 196 | spacing: units.gu(2) |
4824 | 301 | Button { | 197 | ShuffleButton { |
4825 | 302 | id: shuffleRow | 198 | model: albumtrackslist.model |
4808 | 303 | height: units.gu(4) | ||
4809 | 304 | strokeColor: UbuntuColors.green | ||
4810 | 305 | width: units.gu(15) | ||
4811 | 306 | Text { | ||
4812 | 307 | anchors { | ||
4813 | 308 | centerIn: parent | ||
4814 | 309 | } | ||
4815 | 310 | color: "white" | ||
4816 | 311 | elide: Text.ElideRight | ||
4817 | 312 | height: parent.height | ||
4818 | 313 | horizontalAlignment: Text.AlignHCenter | ||
4819 | 314 | // TRANSLATORS: this appears in a button with limited space (around 14 characters) | ||
4820 | 315 | text: i18n.tr("Shuffle") | ||
4821 | 316 | verticalAlignment: Text.AlignVCenter | ||
4822 | 317 | width: parent.width - units.gu(2) | ||
4823 | 318 | } | ||
4826 | 319 | onClicked: { | 199 | onClicked: { |
4827 | 320 | shuffleModel(albumtrackslist.model) // play track | ||
4828 | 321 | |||
4829 | 322 | if (isAlbum && songStackPage.line1 !== i18n.tr("Genre")) { | 200 | if (isAlbum && songStackPage.line1 !== i18n.tr("Genre")) { |
4830 | 323 | Library.addRecent(albumtrackslist.model.get(0, albumtrackslist.model.RoleModelData).album, "album") | 201 | Library.addRecent(albumtrackslist.model.get(0, albumtrackslist.model.RoleModelData).album, "album") |
4831 | 324 | } else if (songStackPage.line1 === i18n.tr("Playlist")) { | 202 | } else if (songStackPage.line1 === i18n.tr("Playlist")) { |
4832 | @@ -330,36 +208,12 @@ | |||
4833 | 330 | recentModel.filterRecent() | 208 | recentModel.filterRecent() |
4834 | 331 | } | 209 | } |
4835 | 332 | } | 210 | } |
4855 | 333 | Button { | 211 | QueueAllButton { |
4856 | 334 | id: queueAllRow | 212 | model: albumtrackslist.model |
4838 | 335 | height: units.gu(4) | ||
4839 | 336 | strokeColor: UbuntuColors.green | ||
4840 | 337 | width: units.gu(15) | ||
4841 | 338 | Text { | ||
4842 | 339 | anchors { | ||
4843 | 340 | centerIn: parent | ||
4844 | 341 | } | ||
4845 | 342 | color: "white" | ||
4846 | 343 | elide: Text.ElideRight | ||
4847 | 344 | height: parent.height | ||
4848 | 345 | horizontalAlignment: Text.AlignHCenter | ||
4849 | 346 | // TRANSLATORS: this appears in a button with limited space (around 14 characters) | ||
4850 | 347 | text: i18n.tr("Queue all") | ||
4851 | 348 | verticalAlignment: Text.AlignVCenter | ||
4852 | 349 | width: parent.width - units.gu(2) | ||
4853 | 350 | } | ||
4854 | 351 | onClicked: addQueueFromModel(albumtrackslist.model) | ||
4857 | 352 | } | 213 | } |
4865 | 353 | Button { | 214 | PlayAllButton { |
4866 | 354 | id: playRow | 215 | model: albumtrackslist.model |
4860 | 355 | color: UbuntuColors.green | ||
4861 | 356 | height: units.gu(4) | ||
4862 | 357 | // TRANSLATORS: this appears in a button with limited space (around 14 characters) | ||
4863 | 358 | text: i18n.tr("Play all") | ||
4864 | 359 | width: units.gu(15) | ||
4867 | 360 | onClicked: { | 216 | onClicked: { |
4868 | 361 | trackClicked(albumtrackslist.model, 0) // play track | ||
4869 | 362 | |||
4870 | 363 | if (isAlbum && songStackPage.line1 !== i18n.tr("Genre")) { | 217 | if (isAlbum && songStackPage.line1 !== i18n.tr("Genre")) { |
4871 | 364 | Library.addRecent(albumtrackslist.model.get(0, albumtrackslist.model.RoleModelData).album, "album") | 218 | Library.addRecent(albumtrackslist.model.get(0, albumtrackslist.model.RoleModelData).album, "album") |
4872 | 365 | } else if (songStackPage.line1 === i18n.tr("Playlist")) { | 219 | } else if (songStackPage.line1 === i18n.tr("Playlist")) { |
4873 | @@ -528,101 +382,4 @@ | |||
4874 | 528 | } | 382 | } |
4875 | 529 | 383 | ||
4876 | 530 | Component.onCompleted: loaded = true | 384 | Component.onCompleted: loaded = true |
4877 | 531 | |||
4878 | 532 | // Edit name of playlist dialog | ||
4879 | 533 | Component { | ||
4880 | 534 | id: editPlaylistDialog | ||
4881 | 535 | Dialog { | ||
4882 | 536 | id: dialogEditPlaylist | ||
4883 | 537 | // TRANSLATORS: this is a title of a dialog with a prompt to rename a playlist | ||
4884 | 538 | title: i18n.tr("Rename playlist") | ||
4885 | 539 | |||
4886 | 540 | property string oldPlaylistName: "" | ||
4887 | 541 | |||
4888 | 542 | TextField { | ||
4889 | 543 | id: playlistName | ||
4890 | 544 | inputMethodHints: Qt.ImhNoPredictiveText | ||
4891 | 545 | placeholderText: i18n.tr("Enter playlist name") | ||
4892 | 546 | } | ||
4893 | 547 | Label { | ||
4894 | 548 | id: editplaylistoutput | ||
4895 | 549 | color: "red" | ||
4896 | 550 | visible: false | ||
4897 | 551 | } | ||
4898 | 552 | |||
4899 | 553 | Button { | ||
4900 | 554 | text: i18n.tr("Change") | ||
4901 | 555 | color: styleMusic.dialog.confirmButtonColor | ||
4902 | 556 | onClicked: { | ||
4903 | 557 | editplaylistoutput.visible = true | ||
4904 | 558 | |||
4905 | 559 | if (playlistName.text.length > 0) { // make sure something is acually inputed | ||
4906 | 560 | console.debug("Debug: User changed name from "+oldPlaylistName+" to "+playlistName.text) | ||
4907 | 561 | |||
4908 | 562 | if (Playlists.renamePlaylist(oldPlaylistName, playlistName.text) === true) { | ||
4909 | 563 | |||
4910 | 564 | if (Library.recentContainsPlaylist(oldPlaylistName)) { | ||
4911 | 565 | Library.recentRenamePlaylist(oldPlaylistName, playlistName.text) | ||
4912 | 566 | } | ||
4913 | 567 | |||
4914 | 568 | line2 = playlistName.text | ||
4915 | 569 | |||
4916 | 570 | playlistChangedHelper() // update recent/playlist models | ||
4917 | 571 | |||
4918 | 572 | PopupUtils.close(dialogEditPlaylist) | ||
4919 | 573 | } | ||
4920 | 574 | else { | ||
4921 | 575 | editplaylistoutput.text = i18n.tr("Playlist already exists") | ||
4922 | 576 | } | ||
4923 | 577 | } | ||
4924 | 578 | else { | ||
4925 | 579 | editplaylistoutput.text = i18n.tr("Please type in a name.") | ||
4926 | 580 | } | ||
4927 | 581 | } | ||
4928 | 582 | } | ||
4929 | 583 | Button { | ||
4930 | 584 | text: i18n.tr("Cancel") | ||
4931 | 585 | color: styleMusic.dialog.cancelButtonColor | ||
4932 | 586 | onClicked: PopupUtils.close(dialogEditPlaylist) | ||
4933 | 587 | } | ||
4934 | 588 | } | ||
4935 | 589 | } | ||
4936 | 590 | |||
4937 | 591 | // Remove playlist dialog | ||
4938 | 592 | Component { | ||
4939 | 593 | id: removePlaylistDialog | ||
4940 | 594 | Dialog { | ||
4941 | 595 | id: dialogRemovePlaylist | ||
4942 | 596 | // TRANSLATORS: this is a title of a dialog with a prompt to delete a playlist | ||
4943 | 597 | title: i18n.tr("Permanently delete playlist?") | ||
4944 | 598 | text: "("+i18n.tr("This cannot be undone")+")" | ||
4945 | 599 | |||
4946 | 600 | property string oldPlaylistName | ||
4947 | 601 | |||
4948 | 602 | Button { | ||
4949 | 603 | text: i18n.tr("Remove") | ||
4950 | 604 | color: styleMusic.dialog.confirmRemoveButtonColor | ||
4951 | 605 | onClicked: { | ||
4952 | 606 | // removing playlist | ||
4953 | 607 | Playlists.removePlaylist(dialogRemovePlaylist.oldPlaylistName) | ||
4954 | 608 | |||
4955 | 609 | if (Library.recentContainsPlaylist(dialogRemovePlaylist.oldPlaylistName)) { | ||
4956 | 610 | Library.recentRemovePlaylist(dialogRemovePlaylist.oldPlaylistName) | ||
4957 | 611 | } | ||
4958 | 612 | |||
4959 | 613 | playlistChangedHelper(true) // update recent/playlist models | ||
4960 | 614 | |||
4961 | 615 | songStackPage.page = undefined | ||
4962 | 616 | PopupUtils.close(dialogRemovePlaylist) | ||
4963 | 617 | |||
4964 | 618 | musicToolbar.goBack() | ||
4965 | 619 | } | ||
4966 | 620 | } | ||
4967 | 621 | Button { | ||
4968 | 622 | text: i18n.tr("Cancel") | ||
4969 | 623 | color: styleMusic.dialog.cancelButtonColor | ||
4970 | 624 | onClicked: PopupUtils.close(dialogRemovePlaylist) | ||
4971 | 625 | } | ||
4972 | 626 | } | ||
4973 | 627 | } | ||
4974 | 628 | } | 385 | } |
4975 | 629 | 386 | ||
4976 | === renamed file 'click/apparmor.json' => 'apparmor.json' | |||
4977 | === removed directory 'click' | |||
4978 | === removed file 'click/CMakeLists.txt' | |||
4979 | --- click/CMakeLists.txt 2014-07-01 23:13:50 +0000 | |||
4980 | +++ click/CMakeLists.txt 1970-01-01 00:00:00 +0000 | |||
4981 | @@ -1,15 +0,0 @@ | |||
4982 | 1 | if(CLICK_MODE) | ||
4983 | 2 | if(NOT BZR_REVNO) | ||
4984 | 3 | set(BZR_REVNO "latest") | ||
4985 | 4 | endif(NOT BZR_REVNO) | ||
4986 | 5 | configure_file(manifest.json.in ${CMAKE_CURRENT_BINARY_DIR}/manifest.json) | ||
4987 | 6 | install(FILES ${CMAKE_CURRENT_BINARY_DIR}/manifest.json apparmor.json | ||
4988 | 7 | music-app-content.json DESTINATION ${CMAKE_INSTALL_PREFIX}) | ||
4989 | 8 | endif(CLICK_MODE) | ||
4990 | 9 | |||
4991 | 10 | # make the click files visible on qtcreator | ||
4992 | 11 | file(GLOB CLICK_FILES | ||
4993 | 12 | RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} | ||
4994 | 13 | *.json *.json.in) | ||
4995 | 14 | |||
4996 | 15 | add_custom_target(com_ubuntu_music_CLICKFiles ALL SOURCES ${CLICK_FILES}) | ||
4997 | 16 | 0 | ||
4998 | === renamed file 'click/manifest.json.in' => 'manifest.json.in' | |||
4999 | === renamed file 'click/music-app-content.json' => 'music-app-content.json' | |||
5000 | === modified file 'tests/autopilot/music_app/__init__.py' |