summaryrefslogtreecommitdiffstats
path: root/qml
diff options
context:
space:
mode:
authorYoann Lopes <yoann.lopes@nokia.com>2012-05-18 02:15:44 +0200
committerYoann Lopes <yoann.lopes@nokia.com>2012-05-18 02:15:44 +0200
commitf932a86631105b6dff7c48708f0f62ca4417a43d (patch)
tree4c8ec4b028a809a56f52b1f32b8f6f0e751e4da7 /qml
parentad5e96ea6b7e8b75972babe870338ceda00349fc (diff)
Added folder support.
Diffstat (limited to 'qml')
-rw-r--r--qml/FolderPage.qml211
-rw-r--r--qml/MainPage.qml16
-rw-r--r--qml/PlaylistMenu.qml64
-rw-r--r--qml/PlaylistPage.qml41
-rw-r--r--qml/SettingsPage.qml8
5 files changed, 304 insertions, 36 deletions
diff --git a/qml/FolderPage.qml b/qml/FolderPage.qml
new file mode 100644
index 0000000..95faaf1
--- /dev/null
+++ b/qml/FolderPage.qml
@@ -0,0 +1,211 @@
+/****************************************************************************
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Yoann Lopes (yoann.lopes@nokia.com)
+**
+** This file is part of the MeeSpot project.
+**
+** Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions
+** are met:
+**
+** Redistributions of source code must retain the above copyright notice,
+** this list of conditions and the following disclaimer.
+**
+** Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in the
+** documentation and/or other materials provided with the distribution.
+**
+** Neither the name of Nokia Corporation and its Subsidiary(-ies) nor the names of its
+** contributors may be used to endorse or promote products derived from
+** this software without specific prior written permission.
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+** FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+** TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+** PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+** LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+** NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+** SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+****************************************************************************/
+
+import QtQuick 1.1
+import com.nokia.meego 1.0
+import QtSpotify 1.0
+import "UIConstants.js" as UI
+
+Page {
+ id: folderPage
+ orientationLock: PageOrientation.LockPortrait
+ anchors.rightMargin: UI.MARGIN_XLARGE
+ anchors.leftMargin: UI.MARGIN_XLARGE
+
+ property variant folder
+ property bool folderDeleted: false
+
+ function folderNotDeleted(page) {
+ if (page.folderDeleted == undefined) {
+ return true;
+ }
+ return !page.folderDeleted;
+ }
+
+ Connections {
+ target: folder
+ onPlaylistDestroyed: {
+ folderPage.folderDeleted = true
+ var foundPage = playlistsTab.find(folderNotDeleted);
+ if (foundPage !== playlistsTab.currentPage)
+ playlistsTab.pop(foundPage, true);
+ }
+ }
+
+ PlaylistMenu {
+ id: menu
+ }
+
+// PlaylistNameSheet {
+// id: newPlaylistSheet
+// title: "Playlist name"
+// onAccepted: { spotifySession.user.createPlaylistInFolder(newPlaylistSheet.playlistName, folderPage.folder); }
+// }
+
+ ListView {
+ id: playlists
+ anchors.fill: parent
+
+ cacheBuffer: 3000
+ model: folder.playlists
+
+ Component.onCompleted: positionViewAtBeginning()
+
+ delegate: PlaylistDelegate {
+ title: (modelData.type === SpotifyPlaylist.Playlist || modelData.type === SpotifyPlaylist.Folder ? modelData.name
+ : (modelData.type === SpotifyPlaylist.Starred ? "Starred"
+ : "Inbox"))
+ subtitle: if (modelData.type == SpotifyPlaylist.Folder) {
+ modelData.playlistCount + " playlist" + (modelData.playlistCount > 1 ? "s" : "")
+ } else {
+ modelData.trackCount + " song" + (modelData.trackCount > 1 ? "s" : "")
+ + ((spotifySession.user ? spotifySession.user.ownsPlaylist(modelData) : false) ? "" : " | by " + modelData.owner)
+ }
+ extraText: modelData.type === SpotifyPlaylist.Folder ? "" : spotifySession.formatDuration(modelData.totalDuration)
+ icon: modelData.collaborative ? "images/icon-m-collaborative-playlist.png" : staticIcon
+ offlineStatus: modelData.offlineStatus
+ availableOffline: modelData.availableOffline
+ downloadProgress: modelData.offlineDownloadProgress
+ unseens: modelData.unseenCount
+ enabled: opacity == 1.0
+ opacity: !spotifySession.offlineMode || modelData.availableOffline || modelData.type === SpotifyPlaylist.Folder ? 1.0 : 0.3
+
+ onClicked: {
+ if (modelData.trackCount > 0) {
+ var component = Qt.createComponent("TracklistPage.qml");
+ if (component.status === Component.Ready) {
+ var playlistPage = component.createObject(playlistsTab, { playlist: modelData });
+ playlistsTab.push(playlistPage);
+ }
+ } else if (modelData.type === SpotifyPlaylist.Folder) {
+ var component2 = Qt.createComponent("FolderPage.qml");
+ if (component2.status === Component.Ready) {
+ var folderPage = component2.createObject(playlistsTab, { folder: modelData });
+ playlistsTab.push(folderPage);
+ }
+ }
+ }
+ onPressAndHold: { menu.playlist = modelData; menu.open(); }
+
+ property string staticIcon
+ Component.onCompleted: {
+ if (modelData.type === SpotifyPlaylist.Playlist)
+ staticIcon = "image://theme/icon-m-music-video-all-songs";
+ else if (modelData.type === SpotifyPlaylist.Starred)
+ staticIcon = "image://theme/icon-m-common-favorite-mark-inverse";
+ else if (modelData.type === SpotifyPlaylist.Inbox)
+ staticIcon = "image://theme/icon-m-toolbar-directory-move-to-white-selected";
+ else if (modelData.type === SpotifyPlaylist.Folder)
+ staticIcon = "image://theme/icon-m-toolbar-directory-selected"
+ }
+ }
+
+ header: ViewHeader {
+ text: folder.name
+ }
+
+// footer: Item {
+// height: visible ? (UI.LIST_ITEM_HEIGHT + separator.height) : 0
+// width: parent.width
+// visible: !spotifySession.offlineMode
+
+// Separator {
+// id: separator
+// anchors.left: parent.left
+// anchors.right: parent.right
+// anchors.top: parent.top
+// }
+
+// Rectangle {
+// id: background
+// anchors.fill: row
+// // Fill page porders
+// anchors.leftMargin: -UI.MARGIN_XLARGE
+// anchors.rightMargin: -UI.MARGIN_XLARGE
+// opacity: mouseArea.pressed ? 1.0 : 0.0
+// color: "#22FFFFFF"
+// }
+
+// Row {
+// id: row
+// width: parent.width
+// anchors.top: separator.bottom
+// anchors.bottom: parent.bottom
+// spacing: UI.LIST_ITEM_SPACING
+
+// Item {
+// id: iconItem
+// anchors.verticalCenter: parent.verticalCenter
+// visible: iconImage.source !== "" ? true : false
+// width: 40
+// height: 40
+
+// Image {
+// id: iconImage
+// anchors.centerIn: parent
+// source: theme.inverted ? "image://theme/icon-m-input-add" : "image://theme/icon-m-common-add"
+// opacity: 0.4
+// }
+// }
+
+// Label {
+// anchors.verticalCenter: parent.verticalCenter
+// font.family: UI.FONT_FAMILY_BOLD
+// font.weight: Font.Bold
+// font.pixelSize: UI.LIST_TILE_SIZE
+// color: theme.inverted ? UI.LIST_TITLE_COLOR_INVERTED : UI.LIST_TITLE_COLOR
+// opacity: 0.4
+// text: "New playlist"
+// }
+// }
+
+// MouseArea {
+// id: mouseArea;
+// anchors.fill: parent
+// onClicked: {
+// newPlaylistSheet.playlistName = "";
+// newPlaylistSheet.open();
+// }
+// }
+// }
+ }
+
+ Scrollbar { listView: playlists }
+}
diff --git a/qml/MainPage.qml b/qml/MainPage.qml
index 828ba38..1fb0fb0 100644
--- a/qml/MainPage.qml
+++ b/qml/MainPage.qml
@@ -79,7 +79,7 @@ Page {
}
}
- property variant playlists: spotifySession.user ? spotifySession.user.playlists : null
+ property variant playlists: spotifySession.user ? spotifySession.user.playlistsFlat : null
Connections {
target: spotifySession.user
onPlaylistsNameChanged: updatePlaylistDialog()
@@ -93,18 +93,18 @@ Page {
if (playlists === null)
return;
+ playlistSelectionDialog.model.append({"name": "New playlist" });
+
for (var i in mainPage.playlists) {
- if (mainPage.playlists[i].type == SpotifyPlaylist.Playlist && spotifySession.user.canModifyPlaylist(mainPage.playlists[i]))
+ if (mainPage.playlists[i].type === SpotifyPlaylist.Playlist && spotifySession.user.canModifyPlaylist(mainPage.playlists[i]))
playlistSelectionDialog.model.append({"name": mainPage.playlists[i].name, "object": mainPage.playlists[i] })
}
-
- playlistSelectionDialog.model.append({"name": "New playlist" });
}
Connections {
target: spotifySession
onConnectionErrorChanged: {
- if (spotifySession.connectionError != SpotifySession.Ok) {
+ if (spotifySession.connectionError !== SpotifySession.Ok) {
errorBanner.text = spotifySession.connectionErrorMessage;
errorBanner.show();
}
@@ -132,7 +132,7 @@ Page {
TabGroup {
id: tabGroup
enabled: !currentTab.busy
- y: player.hidden ? 0 : screen.currentOrientation == Screen.Portrait ? UI.HEADER_DEFAULT_HEIGHT_PORTRAIT
+ y: player.hidden ? 0 : screen.currentOrientation === Screen.Portrait ? UI.HEADER_DEFAULT_HEIGHT_PORTRAIT
: UI.HEADER_DEFAULT_HEIGHT_LANDSCAPE
height: parent.height - y
Behavior on y { NumberAnimation { easing.type: Easing.OutQuart; duration: 500 } }
@@ -200,7 +200,7 @@ Page {
onPressedChanged: {
if (pressed)
- isCurrentTab = (tabGroup.currentTab == searchTab);
+ isCurrentTab = (tabGroup.currentTab === searchTab);
}
onClicked: {
@@ -218,7 +218,7 @@ Page {
onPressedChanged: {
if (pressed)
- isCurrentTab = (tabGroup.currentTab == toplistTab);
+ isCurrentTab = (tabGroup.currentTab === toplistTab);
}
onClicked: {
diff --git a/qml/PlaylistMenu.qml b/qml/PlaylistMenu.qml
index bbe1380..6fd697d 100644
--- a/qml/PlaylistMenu.qml
+++ b/qml/PlaylistMenu.qml
@@ -5,22 +5,22 @@
** Contact: Yoann Lopes (yoann.lopes@nokia.com)
**
** This file is part of the MeeSpot project.
-**
+**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
-**
+**
** Redistributions of source code must retain the above copyright notice,
** this list of conditions and the following disclaimer.
-**
+**
** Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
-**
+**
** Neither the name of Nokia Corporation and its Subsidiary(-ies) nor the names of its
** contributors may be used to endorse or promote products derived from
** this software without specific prior written permission.
-**
+**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
@@ -65,12 +65,19 @@ MyMenu {
QueryDialog {
id: confirmDeleteDialog
+ property bool deleteFolderContent: false
parent: playlistMenu.parent
- titleText: userOwnsPlaylist ? "Delete playlist?" : "Unsubscribe from playlist?"
message: playlist ? playlist.name : ""
acceptButtonText: "Yes"
rejectButtonText: "No"
- onAccepted: { playlist.removeFromContainer() }
+ onAccepted: {
+ if (deleteFolderContent)
+ playlist.deleteFolderContent();
+ else
+ playlist.removeFromContainer()
+ deleteFolderContent = false;
+ }
+ onRejected: deleteFolderContent = false;
}
MyMenuLayout {
@@ -84,7 +91,7 @@ MyMenu {
MyMenuItem {
text: "Add to queue";
onClicked: { playlist.enqueue() }
- visible: (playlist && playlist.trackCount > 0) ? true : false
+ visible: (playlist && (playlist.trackCount > 0 || playlist.type === SpotifyPlaylist.Folder)) ? true : false
}
MyMenuItem {
text: "Rename"
@@ -100,12 +107,43 @@ MyMenu {
}
MyMenuItem {
id: offlineItem
+ visible: (playlist && playlist.type !== SpotifyPlaylist.Folder) ? true : false
onClicked: { playlist.availableOffline = !playlist.availableOffline }
}
MyMenuItem {
+ id: setFolderOfflineItem
+ visible: ((playlist && playlist.type === SpotifyPlaylist.Folder) ? true : false) && !spotifySession.offlineMode
+ text: "Set offline mode for content"
+ onClicked: { playlist.availableOffline = true }
+ }
+ MyMenuItem {
+ id: unsetFolderOfflineItem
+ visible: (playlist && playlist.type === SpotifyPlaylist.Folder) ? true : false
+ text: "Unset offline mode for content"
+ onClicked: { playlist.availableOffline = false }
+ }
+ MyMenuItem {
id: deleteItem
- onClicked: { confirmDeleteDialog.open(); }
- visible: ((playlist && playlist.type == SpotifyPlaylist.Playlist) ? true : false)
+ onClicked: {
+ if (playlist.type === SpotifyPlaylist.Folder) {
+ confirmDeleteDialog.titleText = "Delete folder?";
+ } else {
+ confirmDeleteDialog.titleText = userOwnsPlaylist ? "Delete playlist?" : "Unsubscribe from playlist?";
+ }
+ confirmDeleteDialog.open();
+ }
+ visible: ((playlist && (playlist.type == SpotifyPlaylist.Playlist || playlist.type == SpotifyPlaylist.Folder)) ? true : false)
+ && !spotifySession.offlineMode
+ }
+ MyMenuItem {
+ id: deleteFolderContentItem
+ text: "Delete folder and content"
+ onClicked: {
+ confirmDeleteDialog.deleteFolderContent = true;
+ confirmDeleteDialog.titleText = "Delete folder and its content?";
+ confirmDeleteDialog.open();
+ }
+ visible: ((playlist && playlist.type == SpotifyPlaylist.Folder) ? true : false)
&& !spotifySession.offlineMode
}
}
@@ -113,8 +151,12 @@ MyMenu {
onStatusChanged: {
if (status == DialogStatus.Opening && playlist) {
collabItem.text = (playlist.collaborative ? "Unset" : "Set") + " collaborative";
- deleteItem.text = userOwnsPlaylist ? "Delete" : "Unsubscribe";
offlineItem.text = (playlist.availableOffline ? "Unset" : "Set") + " offline mode"
+ if (playlist.type === SpotifyPlaylist.Folder) {
+ deleteItem.text = "Delete";
+ } else {
+ deleteItem.text = userOwnsPlaylist ? "Delete" : "Unsubscribe";
+ }
}
}
}
diff --git a/qml/PlaylistPage.qml b/qml/PlaylistPage.qml
index 90a85a6..23a11bd 100644
--- a/qml/PlaylistPage.qml
+++ b/qml/PlaylistPage.qml
@@ -83,40 +83,55 @@ Page {
Component.onCompleted: positionViewAtBeginning()
delegate: PlaylistDelegate {
- title: (modelData.type == SpotifyPlaylist.Playlist ? modelData.name
- : (modelData.type == SpotifyPlaylist.Starred ? "Starred"
- : "Inbox"))
- subtitle: modelData.trackCount + " song" + (modelData.trackCount > 1 ? "s" : "")
- + ((spotifySession.user ? spotifySession.user.ownsPlaylist(modelData) : false) ? "" : " | by " + modelData.owner)
- extraText: spotifySession.formatDuration(modelData.totalDuration)
- visible: modelData.isLoaded
+ title: !modelData.isLoaded ? "Loading..." : (modelData.type === SpotifyPlaylist.Playlist || modelData.type === SpotifyPlaylist.Folder ? modelData.name
+ : (modelData.type === SpotifyPlaylist.Starred ? "Starred"
+ : "Inbox"))
+ subtitle: if (!modelData.isLoaded) {
+ "";
+ } else {
+ if (modelData.type === SpotifyPlaylist.Folder) {
+ modelData.playlistCount + " playlist" + (modelData.playlistCount > 1 ? "s" : "")
+ } else {
+ modelData.trackCount + " song" + (modelData.trackCount > 1 ? "s" : "")
+ + ((spotifySession.user ? spotifySession.user.ownsPlaylist(modelData) : false) ? "" : " | by " + modelData.owner)
+ }
+ }
+ extraText: modelData.type === SpotifyPlaylist.Folder || !modelData.isLoaded ? "" : spotifySession.formatDuration(modelData.totalDuration)
icon: modelData.collaborative ? "images/icon-m-collaborative-playlist.png" : staticIcon
offlineStatus: modelData.offlineStatus
availableOffline: modelData.availableOffline
downloadProgress: modelData.offlineDownloadProgress
unseens: modelData.unseenCount
enabled: opacity == 1.0
- opacity: !spotifySession.offlineMode || modelData.availableOffline ? 1.0 : 0.3
+ opacity: (!spotifySession.offlineMode || modelData.availableOffline || modelData.type === SpotifyPlaylist.Folder) && modelData.isLoaded ? 1.0 : 0.3
onClicked: {
if (modelData.trackCount > 0) {
var component = Qt.createComponent("TracklistPage.qml");
- if (component.status == Component.Ready) {
+ if (component.status === Component.Ready) {
var playlistPage = component.createObject(pageStack, { playlist: modelData });
pageStack.push(playlistPage);
}
+ } else if (modelData.type === SpotifyPlaylist.Folder) {
+ var component2 = Qt.createComponent("FolderPage.qml");
+ if (component2.status === Component.Ready) {
+ var folderPage = component2.createObject(pageStack, { folder: modelData });
+ pageStack.push(folderPage);
+ }
}
}
onPressAndHold: { menu.playlist = modelData; menu.open(); }
property string staticIcon
Component.onCompleted: {
- if (modelData.type == SpotifyPlaylist.Playlist)
+ if (modelData.type === SpotifyPlaylist.Playlist)
staticIcon = "image://theme/icon-m-music-video-all-songs";
- else if (modelData.type == SpotifyPlaylist.Starred)
+ else if (modelData.type === SpotifyPlaylist.Starred)
staticIcon = "image://theme/icon-m-common-favorite-mark-inverse";
- else if (modelData.type == SpotifyPlaylist.Inbox)
+ else if (modelData.type === SpotifyPlaylist.Inbox)
staticIcon = "image://theme/icon-m-toolbar-directory-move-to-white-selected";
+ else if (modelData.type === SpotifyPlaylist.Folder)
+ staticIcon = "image://theme/icon-m-toolbar-directory-selected"
}
}
@@ -194,7 +209,7 @@ Page {
section.delegate: Separator {
anchors.left: parent.left
anchors.right: parent.right
- visible: section == "p"
+ visible: section === "p"
}
}
diff --git a/qml/SettingsPage.qml b/qml/SettingsPage.qml
index ad21fb9..dcd0e2d 100644
--- a/qml/SettingsPage.qml
+++ b/qml/SettingsPage.qml
@@ -127,8 +127,8 @@ Page {
ListElement { name: "Normal quality (160kbps)"; value: SpotifySession.HighQuality }
ListElement { name: "High quality (320kbps)"; value: SpotifySession.UltraQuality }
}
- selectedIndex: spotifySession.streamingQuality == SpotifySession.LowQuality ? 0
- : spotifySession.streamingQuality == SpotifySession.HighQuality ? 1 : 2
+ selectedIndex: spotifySession.streamingQuality === SpotifySession.LowQuality ? 0
+ : spotifySession.streamingQuality === SpotifySession.HighQuality ? 1 : 2
onSelectedIndexChanged: spotifySession.streamingQuality = model.get(selectedIndex).value
}
@@ -139,8 +139,8 @@ Page {
ListElement { name: "Normal quality (160kbps)"; value: SpotifySession.HighQuality }
ListElement { name: "High quality (320kbps)"; value: SpotifySession.UltraQuality }
}
- selectedIndex: spotifySession.syncQuality == SpotifySession.LowQuality ? 0
- : spotifySession.syncQuality == SpotifySession.HighQuality ? 1 : 2
+ selectedIndex: spotifySession.syncQuality === SpotifySession.LowQuality ? 0
+ : spotifySession.syncQuality === SpotifySession.HighQuality ? 1 : 2
onSelectedIndexChanged: spotifySession.syncQuality = model.get(selectedIndex).value
}