From 8462a479857ae09254f74d2ef36fec0a39177967 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Sat, 24 Nov 2012 23:38:15 +0100 Subject: [PATCH] some more work on stations --- data/qml/CoverFlip.qml | 82 +++++++++++ data/qml/CoverImage.qml | 25 +++- data/qml/StationScene.qml | 138 +++++++++--------- data/qml/StationView.qml | 69 +-------- resources.qrc | 1 + src/libtomahawk/playlist/PlayableItem.h | 1 + .../dynamic/echonest/EchonestGenerator.cpp | 11 ++ .../dynamic/widgets/DynamicQmlWidget.cpp | 17 ++- .../dynamic/widgets/DynamicQmlWidget.h | 4 + 9 files changed, 207 insertions(+), 141 deletions(-) create mode 100644 data/qml/CoverFlip.qml diff --git a/data/qml/CoverFlip.qml b/data/qml/CoverFlip.qml new file mode 100644 index 000000000..a334f75e7 --- /dev/null +++ b/data/qml/CoverFlip.qml @@ -0,0 +1,82 @@ +import QtQuick 1.1 +import tomahawk 1.0 +import "tomahawkimports" + +PathView { + id: coverView + + // The start coordinates for the covers + // Default is left, centered in height + property int pathStartX: coverSize + property int pathStartY: height / 2 + + // The size of the covers in the path + property int coverSize: 100 + + // emitted when a cover is clicked + signal itemClicked(int index) + + // emitted when a cover is clicked + signal itemPlayPauseClicked(int index) + + preferredHighlightBegin: 0.2 // scene.width / 11000 + preferredHighlightEnd: preferredHighlightBegin + pathItemCount: 5 + //highlightMoveDuration: 500 + + delegate: CoverImage { + height: root.coverSize + width: root.coverSize + + showLabels: true + showMirror: true + artistName: model.artistName + trackName: model.trackName + artworkId: model.coverID + showPlayButton: true + currentyPlayed: mode.itemFromIndex(index).isPlaying + + scale: PathView.itemScale + itemBrightness: PathView.itemBrightness + opacity: PathView.itemOpacity + z: -x + + onPlayClicked: { + coverView.itemPlayPauseClicked(index) + } + + onClicked: { + coverView.itemClicked(index) + } + } + + path: Path { + startX: coverView.pathStartX + startY: coverView.pathStartY + + PathAttribute { name: "itemOpacity"; value: 1 } + PathAttribute { name: "itemBrightness"; value: 1 } + PathAttribute { name: "itemScale"; value: 1 } +// PathLine { x: coverView.pathStartX * 0.9 ; y: coverView.pathStartY * 0.9 } +// PathPercent { value: .2 } +// PathAttribute { name: "itemOpacity"; value: 1 } +// PathAttribute { name: "itemBrightness"; value: 1 } +// PathAttribute { name: "itemScale"; value: 1 } +// PathLine { x: coverView.pathStartX * .5; y: coverView.pathStartY * .5} +// PathPercent { value: .3 } +// PathAttribute { name: "itemOpacity"; value: 1 } +// PathAttribute { name: "itemBrightness"; value: 1 } +// PathAttribute { name: "itemScale"; value: 0.5 } +// // PathLine { x: coverView.pathStartX * .25 ; y: coverView.pathStartY * .25 } +// // PathPercent { value: .75 } +// // PathAttribute { name: "itemOpacity"; value: 1 } +// // PathAttribute { name: "itemBrightness"; value: .5 } +// // PathAttribute { name: "itemScale"; value: 0.4 } + PathLine { x: root.width; y: 0 } + PathPercent { value: 1 } + PathAttribute { name: "itemOpacity"; value: 1 } + PathAttribute { name: "itemBrightness"; value: 0 } + PathAttribute { name: "itemScale"; value: 0.1 } + } + +} diff --git a/data/qml/CoverImage.qml b/data/qml/CoverImage.qml index ecc764ab3..2878d6481 100644 --- a/data/qml/CoverImage.qml +++ b/data/qml/CoverImage.qml @@ -5,8 +5,13 @@ Item { // Should the artist + track labels be painted property bool showLabels: true + // Should the play button be painted on mouse hover? property bool showPlayButton: false + + // if this is true, the play button will be swapped by a pause button + property bool currentyPlayed: false + // Should the mirror be painted? property bool showMirror: false @@ -57,31 +62,35 @@ Item { source: "image://albumart/" + artworkId } - Rectangle { id: textBackground anchors { left: parent.left; right: parent.right; bottom: parent.bottom } - height: 32 - anchors.margins: 5 - color: "black" - opacity: showLabels ? 0.5 : 0 + height: (artistText.height + trackText.height) * 2 + opacity: 1// showLabels ? 1 : 0 radius: 3 + gradient: Gradient { + GradientStop { position: 0.0; color: "#00000000" } + GradientStop { position: 0.5; color: "black" } + GradientStop { position: 1.0; color: "black" } + } } Text { + id: trackText color: "white" font.bold: true text: trackName - anchors { left: textBackground.left; right: textBackground.right; top: textBackground.top } + anchors { left: parent.left; right: parent.right; bottom: artistText.top } anchors.margins: 2 horizontalAlignment: Text.AlignHCenter elide: Text.ElideRight opacity: showLabels ? 1 : 0 } Text { + id: artistText color: "white" text: artistName - anchors { left: textBackground.left; right: textBackground.right; bottom: textBackground.bottom } + anchors { left: parent.left; right: parent.right; bottom: parent.bottom } anchors.margins: 2 horizontalAlignment: Text.AlignHCenter elide: Text.ElideRight @@ -144,7 +153,7 @@ Item { Image { id: playButton visible: showPlayButton ? mouseArea.containsMouse : false - source: "../images/play-rest.png" + source: currentyPlayed ? "../images/pause-rest.png" : "../images/play-rest.png" anchors.centerIn: parent MouseArea { anchors.fill: parent diff --git a/data/qml/StationScene.qml b/data/qml/StationScene.qml index 046c7d557..7221ecb58 100644 --- a/data/qml/StationScene.qml +++ b/data/qml/StationScene.qml @@ -6,7 +6,7 @@ Rectangle { id: scene color: "black" anchors.fill: parent - state: echonestStation.configured ? "list" : "configure" + state: "list" ListModel { id: styleModel @@ -48,79 +48,79 @@ Rectangle { id: stationVisualModel - Column { - height: scene.height - width: scene.width +// Column { +// height: scene.height +// width: scene.width - Row { - height: scene.height / 2 - width: scene.width - spacing: width * .1 +// Row { +// height: scene.height / 2 +// width: scene.width +// spacing: width * .1 - Item { - height: parent.height - width: (parent.width - orText.width - parent.spacing * 2 ) * 2 / 3 - GridView { - id: gridView - anchors.fill: parent - anchors.margins: cellWidth / 2 - model: dummyArtistModel +// Item { +// height: parent.height +// width: (parent.width - orText.width - parent.spacing * 2 ) * 2 / 3 +// GridView { +// id: gridView +// anchors.fill: parent +// anchors.margins: cellWidth / 2 +// model: dummyArtistModel - cellWidth: gridView.width / 4 - 1 // -1 to make sure there is space for 4 items even with rounding error - cellHeight: cellWidth +// cellWidth: gridView.width / 4 - 1 // -1 to make sure there is space for 4 items even with rounding error +// cellHeight: cellWidth - delegate: Item { - height: gridView.cellHeight * .9 - width: height +// delegate: Item { +// height: gridView.cellHeight * .9 +// width: height - CoverImage { - artistName: modelData - anchors.fill: parent +// CoverImage { +// artistName: modelData +// anchors.fill: parent - onClicked: { - echonestStation.setMainControl( EchonestStation.StationTypeArtist, modelData ); - stationListView.incrementCurrentIndex(); - } - } - } - } - } +// onClicked: { +// echonestStation.setMainControl( EchonestStation.StationTypeArtist, modelData ); +// stationListView.incrementCurrentIndex(); +// } +// } +// } +// } +// } - } +// } - Row { - height: scene.height / 2 - width: scene.width * .9 - anchors.horizontalCenter: parent.horizontalCenter - spacing: width * .1 +// Row { +// height: scene.height / 2 +// width: scene.width * .9 +// anchors.horizontalCenter: parent.horizontalCenter +// spacing: width * .1 - TagCloud { - height: parent.height - width: (parent.width - orText.width - parent.spacing * 2 ) * 2 / 3 - model: styleModel//generator.styles() - opacity: echonestStation.configured ? 0 : 1 +// TagCloud { +// height: parent.height +// width: (parent.width - orText.width - parent.spacing * 2 ) * 2 / 3 +// model: styleModel//generator.styles() +// opacity: echonestStation.configured ? 0 : 1 - onTagClicked: { - echonestStation.setMainControl( EchonestStation.StationTypeStyle, item ); - stationListView.incrementCurrentIndex(); - } +// onTagClicked: { +// echonestStation.setMainControl( EchonestStation.StationTypeStyle, item ); +// stationListView.incrementCurrentIndex(); +// } - Behavior on opacity { - NumberAnimation { duration: 300 } - } - } - Text { - id: orText - text: "or" - color: "white" - anchors.verticalCenter: parent.verticalCenter - } - InputField { - anchors.verticalCenter: parent.verticalCenter - width: (parent.width - orText.width - parent.spacing * 2 ) * 1 / 3 - } - } - } +// Behavior on opacity { +// NumberAnimation { duration: 300 } +// } +// } +// Text { +// id: orText +// text: "or" +// color: "white" +// anchors.verticalCenter: parent.verticalCenter +// } +// InputField { +// anchors.verticalCenter: parent.verticalCenter +// width: (parent.width - orText.width - parent.spacing * 2 ) * 1 / 3 +// } +// } +// } StationView { coverSize: Math.min(scene.height, scene.width) / 2 @@ -147,12 +147,12 @@ Rectangle { orientation: ListView.Horizontal model: stationVisualModel interactive: false - highlightMoveDuration: 400 + //highlightMoveDuration: 400 - Component.onCompleted: { - if ( echonestStation.configured ) { - currentIndex = 1 - } - } +// currentIndex: 1 + +// Component.onCompleted: { +// currentIndex = 1 +// } } } diff --git a/data/qml/StationView.qml b/data/qml/StationView.qml index e4c8318ac..2b5bbfe73 100644 --- a/data/qml/StationView.qml +++ b/data/qml/StationView.qml @@ -8,79 +8,24 @@ Item { signal configure() - PathView { + + CoverFlip { id: coverView anchors.fill: parent - anchors.rightMargin: parent.width / 3 - - preferredHighlightBegin: 0.2 // scene.width / 11000 - preferredHighlightEnd: preferredHighlightBegin - pathItemCount: 5 - //highlightMoveDuration: 500 + anchors.leftMargin: parent.width / 2 model: dynamicModel - currentIndex: currentlyPlayedIndex - property int pathStartX: width / 2 - property int pathStartY: height / 2 - - delegate: CoverImage { - height: root.coverSize - width: root.coverSize - - showLabels: false - showMirror: true - //artistName: model.artistName - //trackName: model.trackName - artworkId: model.coverID - - scale: PathView.itemScale - itemBrightness: PathView.itemBrightness - opacity: PathView.itemOpacity - z: x - - onClicked: { - if ( currentlyPlayedIndex !==-1 ) { - echonestStation.playItem( index ) - } - } - } - - path: Path { - startX: coverView.pathStartX - startY: coverView.pathStartY - - PathAttribute { name: "itemOpacity"; value: 0 } - PathAttribute { name: "itemBrightness"; value: 0 } - PathAttribute { name: "itemScale"; value: 1.5 } - PathLine { x: coverView.pathStartX * 0.9 ; y: coverView.pathStartY * 0.9 } - PathPercent { value: .2 } - PathAttribute { name: "itemOpacity"; value: 1 } - PathAttribute { name: "itemBrightness"; value: 1 } - PathAttribute { name: "itemScale"; value: 1 } - PathLine { x: coverView.pathStartX * .5; y: coverView.pathStartY * .5} - PathPercent { value: .3 } - PathAttribute { name: "itemOpacity"; value: 1 } - PathAttribute { name: "itemBrightness"; value: 1 } - PathAttribute { name: "itemScale"; value: 0.5 } - // PathLine { x: coverView.pathStartX * .25 ; y: coverView.pathStartY * .25 } - // PathPercent { value: .75 } - // PathAttribute { name: "itemOpacity"; value: 1 } - // PathAttribute { name: "itemBrightness"; value: .5 } - // PathAttribute { name: "itemScale"; value: 0.4 } - PathLine { x: 0; y: 0 } - PathPercent { value: 1 } - PathAttribute { name: "itemOpacity"; value: 1 } - PathAttribute { name: "itemBrightness"; value: 0 } - PathAttribute { name: "itemScale"; value: 0.1 } + onItemPlayPauseClicked: { + rootView.playItem(index) } } Item { - anchors { top: parent.top; right: parent.right; bottom: parent.bottom } + anchors { top: parent.top; left: parent.left; bottom: parent.bottom } anchors.margins: 50 - width: scene.width / 3 + width: scene.width / 2 Column { anchors { left: parent.left; top: parent.top; right: parent.right } diff --git a/resources.qrc b/resources.qrc index 6199db7d4..3364a7fb3 100644 --- a/resources.qrc +++ b/resources.qrc @@ -171,5 +171,6 @@ data/qml/tomahawkimports/InputField.qml data/qml/tomahawkimports/Button.qml data/qml/tomahawkimports/DoubleSlider.qml + data/qml/CoverFlip.qml diff --git a/src/libtomahawk/playlist/PlayableItem.h b/src/libtomahawk/playlist/PlayableItem.h index ba49da50b..607801126 100644 --- a/src/libtomahawk/playlist/PlayableItem.h +++ b/src/libtomahawk/playlist/PlayableItem.h @@ -33,6 +33,7 @@ Q_OBJECT Q_PROPERTY(QString name READ name NOTIFY dataChanged) Q_PROPERTY(QString artistName READ artistName NOTIFY dataChanged) Q_PROPERTY(QString albumName READ albumName NOTIFY dataChanged) + Q_PROPERTY(bool isPlaying READ isPlaying NOTIFY dataChanged) public: ~PlayableItem(); diff --git a/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.cpp b/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.cpp index f10637a4a..6c0232f83 100644 --- a/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.cpp +++ b/src/libtomahawk/playlist/dynamic/echonest/EchonestGenerator.cpp @@ -167,6 +167,17 @@ EchonestGenerator::generate( int number ) // qWarning() << "Got invalid controls!" << e.what(); // emit error( "Filters are not valid", e.what() ); // } + + + QList< query_ptr > queries; + queries << Query::get("Colour Haze", "All", QString(), uuid(), true); + queries << Query::get("Colour Haze", "Sun", QString(), uuid(), true); + queries << Query::get("Colour Haze", "Zen", QString(), uuid(), true); + queries << Query::get("Colour Haze", "Outside", QString(), uuid(), true); + queries << Query::get("Colour Haze", "Dirt", QString(), uuid(), true); + + emit generated( queries ); + } diff --git a/src/libtomahawk/playlist/dynamic/widgets/DynamicQmlWidget.cpp b/src/libtomahawk/playlist/dynamic/widgets/DynamicQmlWidget.cpp index ce57a655a..bfb055acb 100644 --- a/src/libtomahawk/playlist/dynamic/widgets/DynamicQmlWidget.cpp +++ b/src/libtomahawk/playlist/dynamic/widgets/DynamicQmlWidget.cpp @@ -42,8 +42,6 @@ DynamicQmlWidget::DynamicQmlWidget( const dynplaylist_ptr& playlist, QWidget* pa m_model->loadPlaylist( m_playlist ); - // Initially seed the playlist - m_playlist->generator()->generate( 20 ); qDebug() << "###got" << m_playlist->generator()->controls().size() << "controls"; @@ -55,6 +53,7 @@ DynamicQmlWidget::DynamicQmlWidget( const dynplaylist_ptr& playlist, QWidget* pa rootContext()->setContextProperty( "dynamicModel", m_proxyModel ); rootContext()->setContextProperty( "generator", m_playlist->generator().data() ); + rootContext()->setContextProperty( "rootView", this ); setSource( QUrl( "qrc" RESPATH "qml/StationScene.qml" ) ); @@ -67,6 +66,9 @@ DynamicQmlWidget::DynamicQmlWidget( const dynplaylist_ptr& playlist, QWidget* pa connect( AudioEngine::instance(), SIGNAL( started( Tomahawk::result_ptr ) ), this, SLOT( trackStarted() ) ); connect( AudioEngine::instance(), SIGNAL( playlistChanged( Tomahawk::playlistinterface_ptr ) ), this, SLOT( playlistChanged( Tomahawk::playlistinterface_ptr ) ) ); + // Initially seed the playlist + m_playlist->generator()->generate( 20 ); + } @@ -114,6 +116,17 @@ playlist_ptr DynamicQmlWidget::playlist() const return m_model->playlist(); } +void DynamicQmlWidget::playItem(int index) +{ + qDebug() << "playItem called for cover" << index; + AudioEngine::instance()->playItem( m_proxyModel->playlistInterface(), m_proxyModel->itemFromIndex( index )->result() ); +} + +void DynamicQmlWidget::pause() +{ + AudioEngine::instance()->pause(); +} + void DynamicQmlWidget::currentItemChanged( const QPersistentModelIndex ¤tIndex ) { rootContext()->setContextProperty( "currentlyPlayedIndex", m_proxyModel->mapFromSource( currentIndex ).row() ); diff --git a/src/libtomahawk/playlist/dynamic/widgets/DynamicQmlWidget.h b/src/libtomahawk/playlist/dynamic/widgets/DynamicQmlWidget.h index 0b36ea56f..a9181d337 100644 --- a/src/libtomahawk/playlist/dynamic/widgets/DynamicQmlWidget.h +++ b/src/libtomahawk/playlist/dynamic/widgets/DynamicQmlWidget.h @@ -54,6 +54,10 @@ public: playlist_ptr playlist() const; +public slots: + void playItem(int index); + void pause(); + private slots: void currentItemChanged( const QPersistentModelIndex ¤tIndex ); void tracksGenerated( const QList< Tomahawk::query_ptr>& queries );