diff --git a/qml/FakeSearchPage.qml b/qml/FakeSearchPage.qml index 8ee496f..8d2ce68 100644 --- a/qml/FakeSearchPage.qml +++ b/qml/FakeSearchPage.qml @@ -118,13 +118,13 @@ Page { id: busyFooter Item { id: busyFooterContainer - width: resultsList.width - height: musicStreamer.searching && resultsList.count > 0 ? 48 * ScreenValues.dp : 0 + width: listResults.width + height: musicStreamer.searching && listResults.count > 0 ? 48 * ScreenValues.dp : 0 Connections { target: musicStreamer onSearchingChanged: { - if (musicStreamer.searching && resultsList.count > 0) + if (musicStreamer.searching && listResults.count > 0) busyFooterContainer.height = 48 * ScreenValues.dp else busyFooterContainer.height = 0 @@ -132,9 +132,9 @@ Page { } Connections { - target: resultsList + target: listResults onCountChanged: { - if (musicStreamer.searching && resultsList.count > 0) + if (musicStreamer.searching && listResults.count > 0) busyFooterContainer.height = 48 * ScreenValues.dp else busyFooterContainer.height = 0 @@ -172,7 +172,7 @@ Page { flickableItem.interactive: true; focus: true ListView { - id: resultsList + id: listResults anchors.fill: parent @@ -202,7 +202,7 @@ Page { BusyIndicator { id: busyIndicatorComponent anchors.centerIn: parent - running: musicStreamer.searching && resultsList.count == 0 + running: musicStreamer.searching && listResults.count == 0 height: (applicationWindow.height > applicationWindow.width ? applicationWindow.width : applicationWindow.height) * 0.4 width: height diff --git a/qml/ImageButton.qml b/qml/ImageButton.qml index faa4580..54e1938 100644 --- a/qml/ImageButton.qml +++ b/qml/ImageButton.qml @@ -18,7 +18,6 @@ Item { id: mouseArea anchors.fill: parent - onClicked: root.clicked() } } diff --git a/qml/MainPage.qml b/qml/MainPage.qml index 8df1ccc..fecb126 100644 --- a/qml/MainPage.qml +++ b/qml/MainPage.qml @@ -92,12 +92,12 @@ Page { if (index < playlist.count - 1) { /// Will copy next item data, no need to change index - playbackControls.song = playlist.get(index + 1).name + " - " + playlist.get(index + 1).artist + "" + playbackControls.song = playlist.get(index + 1).name + " - " + playlist.get(index + 1).comment + "" audioElement.source = playlist.get(index + 1).url audioElement.play() } else if (index - 1 >= 0) { /// Will copy previous item data, update index to -1 - playbackControls.song = playlist.get(index - 1).name + " - " + playlist.get(index - 1).artist + "" + playbackControls.song = playlist.get(index - 1).name + " - " + playlist.get(index - 1).comment + "" audioElement.source = playlist.get(index - 1).url audioElement.index = audioElement.index - 1 audioElement.play() @@ -116,6 +116,32 @@ Page { } } + Label { + anchors { + top: parent.top + left: parent.left + right: parent.right + bottom: parent.bottom + margins: 8 * ScreenValues.dp + } + + text: qsTr("You have no music on the playlist") + visible: songList.count === 0 + + color: Theme.mainTextColor + + font { + pixelSize: 28 * ScreenValues.dp + family: Theme.fontFamily + } + + horizontalAlignment: "AlignHCenter" + verticalAlignment: "AlignVCenter" + + wrapMode: "Wrap" + elide: "ElideRight" + } + //Component.onCompleted: playlist.append({"name" : "First Song", //"artist" : "First Group", "length" : "3:31", "comment" : "this is a test", //"code" : "XASDDASD", "url": "invalid", "picture": "crazytest"}) diff --git a/qml/PlaylistDelegate.qml b/qml/PlaylistDelegate.qml index 2355799..7bdcf39 100644 --- a/qml/PlaylistDelegate.qml +++ b/qml/PlaylistDelegate.qml @@ -48,11 +48,14 @@ Item { left: parent.left; leftMargin: 8 * ScreenValues.dp } - font.pixelSize: 18 * ScreenValues.dp + font { + pixelSize: 18 * ScreenValues.dp + family: Theme.fontFamily + } color: Style.TEXT_COLOR_DARK elide: Text.ElideRight - text: model.name + " - " + model.group + "" + text: model.name width: parent.width renderType: Text.NativeRendering // TODO: add a dialog to show full name in case it's too long ??? @@ -65,7 +68,10 @@ Item { left: parent.left; leftMargin: 8 * ScreenValues.dp } - font.pixelSize: 12 * ScreenValues.dp + font { + pixelSize: 12 * ScreenValues.dp + family: Theme.fontFamily + } elide: Text.ElideRight color: Style.TEXT_SECONDARY_COLOR_DARK diff --git a/qml/SearchPage.qml b/qml/SearchPage.qml index d7a2dbf..2a1ecce 100644 --- a/qml/SearchPage.qml +++ b/qml/SearchPage.qml @@ -9,15 +9,17 @@ Page { property var shareModel function search() { - if (!musicStreamer.searching) + if (!musicStreamer.searching) { if (textEdit.text.length > 0) { + labelNoResults.opacity = 0 musicStreamer.search(textEdit.text) Qt.inputMethod.hide() } + } } onActivated: { - if (!resultsList.count) + if (!listResults.count) textEdit.focus = true else Qt.inputMethod.hide() @@ -33,6 +35,7 @@ Page { onClicked: stackView.pop() } + /// TODO: add X button to clear this TextField { id: textEdit @@ -122,28 +125,8 @@ Page { id: busyFooter Item { id: busyFooterContainer - width: resultsList.width - height: musicStreamer.searching && resultsList.count > 0 ? 48 * ScreenValues.dp : 0 - - Connections { - target: musicStreamer - onSearchingChanged: { - if (musicStreamer.searching && resultsList.count > 0) - busyFooterContainer.height = 48 * ScreenValues.dp - else - busyFooterContainer.height = 0 - } - } - - Connections { - target: resultsList - onCountChanged: { - if (musicStreamer.searching && resultsList.count > 0) - busyFooterContainer.height = 48 * ScreenValues.dp - else - busyFooterContainer.height = 0 - } - } + width: listResults.width + height: musicStreamer.activeConnections > 0 && listResults.count > 0 ? 48 * ScreenValues.dp : 0 BusyIndicator { anchors.centerIn: parent @@ -176,7 +159,7 @@ Page { flickableItem.interactive: true; focus: true ListView { - id: resultsList + id: listResults anchors.fill: parent @@ -216,13 +199,14 @@ Page { } } + /// TODO: consider adding a button on the bottom to fetch more if list doesn't cover whole page + onContentYChanged: { Qt.inputMethod.hide() if (contentHeight != 0) { // if (!musicStreamer.searching && ((contentY + height) / contentHeight) > 0.85) - if (!musicStreamer.searching && atYEnd) - musicStreamer.fetchMore() - + if (musicStreamer.activeConnections === 0 && atYEnd) + musicStreamer.fetchMoreResulst() } } } @@ -237,7 +221,7 @@ Page { BusyIndicator { id: busyIndicatorComponent anchors.centerIn: parent - running: musicStreamer.searching && resultsList.count == 0 + running: (musicStreamer.searching || musicStreamer.activeConnections > 0) && listResults.count == 0 height: (applicationWindow.height > applicationWindow.width ? applicationWindow.width : applicationWindow.height) * 0.4 width: height @@ -327,6 +311,42 @@ Page { progressLabel.progress = progress progressLabel.name = name } + + onNoResults: { + if (listResults.count === 0) + labelNoResults.opacity = 1 + } + } + } + + Label { + id: labelNoResults + + anchors { + top: parent.top + left: parent.left + right: parent.right + bottom: parent.bottom + margins: 8 * ScreenValues.dp } + + color: Theme.mainTextColor + + elide: "ElideRight" + wrapMode: "Wrap" + + font { + pixelSize: 28 * ScreenValues.dp + family: Theme.fontFamily + } + + horizontalAlignment: "AlignHCenter" + verticalAlignment: "AlignVCenter" + + text: qsTr("No results") + + opacity: 0 + + Behavior on opacity { NumberAnimation { } } } } diff --git a/qml/SongDelegate.qml b/qml/SongDelegate.qml index 4ad614b..9b3727e 100644 --- a/qml/SongDelegate.qml +++ b/qml/SongDelegate.qml @@ -48,10 +48,10 @@ Item { } antialiasing: true - Layout.preferredHeight: 68 * ScreenValues.dp - Layout.preferredWidth: 68 * ScreenValues.dp + Layout.preferredHeight: 0 + Layout.preferredWidth: 0 fillMode: Image.PreserveAspectCrop - source: "http://www.goear.com/band/picture/" + model.picture + source: "" } Item { @@ -74,7 +74,7 @@ Item { Layout.fillWidth: true color: Style.TEXT_COLOR_DARK elide: Text.ElideRight - text: model.name + " - " + model.artist + "" + text: model.name renderType: Text.NativeRendering maximumLineCount: 1 } @@ -96,6 +96,7 @@ Item { width: parent.width renderType: Text.NativeRendering maximumLineCount: 1 + linkColor: Style.TEXT_SECONDARY_COLOR_DARK } Rectangle { diff --git a/qml/main.qml b/qml/main.qml index be2f669..8743a02 100644 --- a/qml/main.qml +++ b/qml/main.qml @@ -29,7 +29,7 @@ ApplicationWindow { else audio.index = 0 - playbackControls.song = playlist.get(audio.index).name + " - " + playlist.get(audio.index).artist + "" + playbackControls.song = playlist.get(audio.index).name + " - " + playlist.get(audio.index).comment + "" audio.source = playlist.get(audio.index).url audio.play() } @@ -40,7 +40,7 @@ ApplicationWindow { else audio.index = playlist.count - 1 - playbackControls.song = playlist.get(audio.index).name + " - " + playlist.get(audio.index).artist + "" + playbackControls.song = playlist.get(audio.index).name + " - " + playlist.get(audio.index).comment + "" audio.source = playlist.get(audio.index).url audio.play() } @@ -120,7 +120,7 @@ ApplicationWindow { onRowsInserted: { // If new item is first on list, play it if (count === 1) { - playbackControls.song = playlist.get(audio.index).name + " - " + playlist.get(audio.index).artist + "" + playbackControls.song = playlist.get(audio.index).name + " - " + playlist.get(audio.index).comment + "" audio.source = playlist.get(audio.index).url audio.play() } else if (audio.status == Audio.EndOfMedia) { diff --git a/src/downloader.cpp b/src/downloader.cpp index c2198f8..37d0438 100644 --- a/src/downloader.cpp +++ b/src/downloader.cpp @@ -15,7 +15,8 @@ QString Downloader::DownloadUrl("http://www.goear.com/action/sound/get/"); Downloader::Downloader(QObject *parent) : QObject(parent), - m_downloading(false) + m_downloading(false), + m_activeConnections(0) { m_netAccess = new QNetworkAccessManager(this); connect(m_netAccess, SIGNAL(finished(QNetworkReply*)), SLOT(downloadFinished(QNetworkReply*))); @@ -60,6 +61,7 @@ void Downloader::download(const QString &urlString) request.setRawHeader("User-Agent", " Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:29.0) Gecko/20100101 Firefox/29.0"); m_nreply = m_netAccess->get(request); + setActiveConnections(m_activeConnections + 1); connect(m_nreply, SIGNAL(downloadProgress(qint64, qint64)), this, SLOT(downloadProgressChanged(qint64, qint64))); } @@ -71,6 +73,7 @@ void Downloader::search(const QString &term) void Downloader::downloadFinished(QNetworkReply *reply) { + setActiveConnections(m_activeConnections - 1); if (reply->url().toString().startsWith(COOKIE_CREATOR_URL)) { mCookies = m_netAccess->cookieJar()->cookiesForUrl(reply->url()); @@ -125,7 +128,10 @@ void Downloader::downloadFinished(QNetworkReply *reply) if (mimeType.contains("text/html")) { QString songs(reply->readAll()); - int count = qMin(songs.count("listen/") / 2, 10); + int count = songs.count("listen/") / 3; + + if (count == 0) + emit noResults(); QString hasMore = ""; QString searchTerm = "
    "; @@ -172,6 +178,8 @@ void Downloader::downloadFinished(QNetworkReply *reply) songs = decodeHtml(songs); + int addedSongs = 0; + for (int i = 0; i < count; ++i) { searchTerm = "listen/"; closingTerm = "/"; @@ -260,11 +268,18 @@ void Downloader::downloadFinished(QNetworkReply *reply) // << "COMMENT:" << comment << "KBPS:" << kbps << "CODE:" << code // << "PICTURE:" << picture; - songs = songs.mid(songs.indexOf("
  1. ")); + songs = songs.mid(songs.indexOf("
  2. 1) { + emit songFound(title, artist, length, comment, kbps.toInt(), code, picture, hits.replace(",", "").toLong()); + getDownloadLink(code); + addedSongs++; + } } + + if (addedSongs == 0) + emit noResults(); + } else if (mimeType == "audio/mpeg") { qDebug() << "Writing file"; QString name(m_songsToDownload.value(reply->url().toString()).toString()); @@ -308,6 +323,20 @@ void Downloader::downloadFinished(QNetworkReply *reply) reply->deleteLater(); } +int Downloader::activeConnections() const +{ + return m_activeConnections; +} + +void Downloader::setActiveConnections(int activeConnections) +{ + if (m_activeConnections == activeConnections) + return; + + m_activeConnections = activeConnections; + emit activeConnectionsChanged(); +} + QString Downloader::decodeHtml(const QString &html) { QString decodedHtml(html); diff --git a/src/downloader.h b/src/downloader.h index 32c3de0..0de640c 100644 --- a/src/downloader.h +++ b/src/downloader.h @@ -24,6 +24,7 @@ class Downloader : public QObject Q_OBJECT Q_PROPERTY(bool downloading READ isDownloading NOTIFY downloadingChanged) + Q_PROPERTY(int activeConnections READ activeConnections NOTIFY activeConnectionsChanged) public: explicit Downloader(QObject *parent = 0); @@ -34,6 +35,9 @@ class Downloader : public QObject bool isDownloading() const; + int activeConnections() const; + void setActiveConnections(int activeConnections); + public slots: void downloadSong(const QString &name, const QString &url); void getDownloadLink(const QString &code); @@ -54,6 +58,8 @@ public slots: void searchHasNoMoreResults(); void downloadingChanged(); void progressChanged(float progress, const QString &name); + void activeConnectionsChanged(); + void noResults(); private: QNetworkAccessManager *m_netAccess; @@ -62,6 +68,7 @@ public slots: QNetworkReply *m_nreply; bool m_downloading; QList mCookies; + int m_activeConnections; void setDownloading(bool downloading); diff --git a/src/musicstreamer.cpp b/src/musicstreamer.cpp index 7c078e4..7fabf4f 100644 --- a/src/musicstreamer.cpp +++ b/src/musicstreamer.cpp @@ -27,6 +27,8 @@ MusicStreamer::MusicStreamer(QObject *parent) : connect(mDownloader, SIGNAL(downloadingChanged()), SLOT(emitDownloadingChanged())); connect(mDownloader, SIGNAL(progressChanged(float, QString)), SIGNAL(progressChanged(float, QString))); connect(mDownloader, SIGNAL(serverError()), SIGNAL(serverError())); + connect(mDownloader, SIGNAL(activeConnectionsChanged()), SIGNAL(activeConnectionsChanged())); + connect(mDownloader, SIGNAL(noResults()), SIGNAL(noResults())); } void MusicStreamer::downloadSong(const QString &name, const QString &url) @@ -132,6 +134,16 @@ QHash MusicStreamer::roleNames() const return roles; } +int MusicStreamer::activeConnections() const +{ + return mDownloader->activeConnections(); +} + +void MusicStreamer::setActiveConnections(int activeConnections) +{ + mDownloader->setActiveConnections(activeConnections); +} + void MusicStreamer::searchEnded() { setSearching(false); @@ -172,7 +184,7 @@ void MusicStreamer::setSearching(bool searching) void MusicStreamer::lastSearchHasMoreResults(const QString &url) { - qDebug() << "more results: " << url; + // qDebug() << "more results: " << url; mLastSearchHasMoreResults = url; } @@ -181,14 +193,12 @@ void MusicStreamer::lastSearchHasNoMoreResults() mLastSearchHasMoreResults.clear(); } -void MusicStreamer::fetchMore() +void MusicStreamer::fetchMoreResulst() { - // if (fetched < 3) if (!mLastSearchHasMoreResults.isEmpty() && !mSearching) { setSearching(true); mDownloader->download(mLastSearchHasMoreResults); } - // fetched++; } void MusicStreamer::share(const QString &name, const QString &url) diff --git a/src/musicstreamer.h b/src/musicstreamer.h index f44d7e1..8978db6 100644 --- a/src/musicstreamer.h +++ b/src/musicstreamer.h @@ -13,6 +13,7 @@ class MusicStreamer : public QAbstractListModel Q_PROPERTY(bool searching READ searching NOTIFY searchingChanged) //Q_PROPERTY(bool serverError READ serverError NOTIFY serverErrorChanged) Q_PROPERTY(bool downloading READ isDownloading NOTIFY downloadingChanged) + Q_PROPERTY(int activeConnections READ activeConnections NOTIFY activeConnectionsChanged) public: enum DownloaderRoles { @@ -31,7 +32,7 @@ class MusicStreamer : public QAbstractListModel Q_INVOKABLE void downloadSong(const QString &name, const QString &url); Q_INVOKABLE void search(const QString &term); - Q_INVOKABLE void fetchMore(); + Q_INVOKABLE void fetchMoreResulst(); Q_INVOKABLE void share(const QString &name, const QString &url); QObjectList songs(); @@ -48,6 +49,9 @@ class MusicStreamer : public QAbstractListModel bool isDownloading() const; + int activeConnections() const; + void setActiveConnections(int activeConnections); + signals: void songsChanged(); void searchingChanged(); @@ -55,6 +59,8 @@ class MusicStreamer : public QAbstractListModel void serverError(); void downloadingChanged(); void progressChanged(float progress, const QString &name); + void activeConnectionsChanged(); + void noResults(); protected: QHash roleNames() const;