diff --git a/data/qml/StationScene.qml b/data/qml/StationScene.qml index af295b207..5595f7414 100644 --- a/data/qml/StationScene.qml +++ b/data/qml/StationScene.qml @@ -1,37 +1,162 @@ import QtQuick 1.1 Rectangle { + id: scene color: "black" anchors.fill: parent -// height: 200 -// width: 200 + + property int coverSize: 230 + + Component { + id: coverImage + + Rectangle { + height: scene.coverSize + width: scene.coverSize + color: scene.color + border.color: scene.color + border.width: 2 + + property string artistName + property string trackName + property string artworkId + + Image { + anchors.fill: parent + anchors.margins: parent.border.width + source: "image://albumart/" + parent.artworkId + onSourceChanged: print("!*!*!*!*!*!*!*!*!", source) + } + + Rectangle { + id: textBackground + anchors { left: parent.left; right: parent.right; bottom: parent.bottom } + height: 32 + anchors.margins: 5 + color: "black" + opacity: 0.5 + radius: 3 + + } + Text { + color: "white" + font.bold: true + text: trackName + anchors { left: textBackground.left; right: textBackground.right; top: textBackground.top } + anchors.margins: 2 + horizontalAlignment: Text.AlignHCenter + elide: Text.ElideRight + } + Text { + color: "white" + text: artistName + anchors { left: textBackground.left; right: textBackground.right; bottom: textBackground.bottom } + anchors.margins: 2 + horizontalAlignment: Text.AlignHCenter + elide: Text.ElideRight + } + + MouseArea { + anchors.fill: parent + onClicked: print("cover clicked") + } + } + } + + Component { + id: mirroredDelegate + + Item { + id: mirrorItem + height: scene.coverSize + width: scene.coverSize + + z: x + scale: PathView.itemScale + + property double itemOpacity: PathView.itemOpacity + property double shadowOp: PathView.shadowOpacity + + Loader { + id: normalCover + sourceComponent: coverImage + opacity: parent.itemOpacity + onLoaded: { + item.trackName = trackName + item.artistName = artistName + item.artworkId = index + } + } + Loader { + id: mirroredCover + sourceComponent: coverImage + opacity: parent.itemOpacity + onLoaded: { + item.trackName = trackName + item.artistName = artistName + item.artworkId = index + } + transform : [ + Rotation { + angle: 180; origin.y: scene.coverSize + axis.x: 1; axis.y: 0; axis.z: 0 + } + ] + } + + Rectangle { + color: scene.color + anchors.fill: parent + opacity: mirrorItem.shadowOp + } + Rectangle { + color: scene.color + height: scene.coverSize + width: scene.coverSize + anchors.centerIn: parent + anchors.verticalCenterOffset: scene.coverSize + gradient: Gradient { + // TODO: no clue how to get the RGB component of the container rectangle color + // For now the Qt.rgba needs to be manually updated to match scene.color + GradientStop { position: 0.0; color: Qt.rgba(0, 0, 0, mirrorItem.shadowOp + ( (1 - mirrorItem.shadowOp) * .4)) } + GradientStop { position: 0.5; color: scene.color } + } + } + } + } PathView { id: view anchors.fill: parent highlight: appHighlight - preferredHighlightBegin: 0.5 - preferredHighlightEnd: 0.5 - focus: true - model: dynamicModel + preferredHighlightBegin: 0.1 + preferredHighlightEnd: 0.1 + pathItemCount: 3 + highlightMoveDuration: 500 - delegate: Rectangle { - height: 200 - width: 200 - color: "blue" - border.color: "black" - border.width: 2 - } + model: dynamicModel + currentIndex: currentlyPlayedIndex + + delegate: mirroredDelegate + + + onCurrentIndexChanged: print("***************************************** current index:", currentIndex) path: Path { - startX: 0 - startY: 0 -// PathAttribute { name: "iconScale"; value: 0.5 } - PathQuad { x: 400; y: 150; controlX: 200; controlY: 75 } -// PathAttribute { name: "iconScale"; value: 1.0 } -// PathQuad { x: 390; y: 50; controlX: 350; controlY: 200 } -// PathAttribute { name: "iconScale"; value: 0.5 } + startX: scene.width / 2 + 20 + startY: 155 + PathAttribute { name: "itemOpacity"; value: 0 } + PathAttribute { name: "shadowOpacity"; value: 0 } + PathAttribute { name: "itemScale"; value: 1.0 } + PathLine { x: scene.width / 2; y: 150 } + PathAttribute { name: "itemOpacity"; value: 1 } + PathAttribute { name: "shadowOpacity"; value: 0 } + PathAttribute { name: "itemScale"; value: 1.0 } + PathLine { x: 100; y: 100;} + PathAttribute { name: "itemOpacity"; value: 1 } + PathAttribute { name: "shadowOpacity"; value: 1 } + PathAttribute { name: "itemScale"; value: 0.75 } } } } diff --git a/src/libtomahawk/playlist/PlayableModel.cpp b/src/libtomahawk/playlist/PlayableModel.cpp index 02f2c1c5e..4cc14043c 100644 --- a/src/libtomahawk/playlist/PlayableModel.cpp +++ b/src/libtomahawk/playlist/PlayableModel.cpp @@ -45,7 +45,8 @@ PlayableModel::PlayableModel( QObject* parent, bool loading ) { QHash roleNames; - roleNames.insert(Qt::DisplayRole, "label"); + roleNames.insert(ArtistRole, "artistName"); + roleNames.insert(TrackRole, "trackName"); setRoleNames(roleNames); connect( AudioEngine::instance(), SIGNAL( started( Tomahawk::result_ptr ) ), SLOT( onPlaybackStarted( Tomahawk::result_ptr ) ), Qt::DirectConnection ); @@ -332,6 +333,7 @@ PlayableModel::setCurrentItem( const QModelIndex& index ) m_currentIndex = QModelIndex(); m_currentUuid = QString(); } + emit currentItemChanged( m_currentIndex ); } diff --git a/src/libtomahawk/playlist/PlayableModel.h b/src/libtomahawk/playlist/PlayableModel.h index ba0eaf55b..9202a5ade 100644 --- a/src/libtomahawk/playlist/PlayableModel.h +++ b/src/libtomahawk/playlist/PlayableModel.h @@ -134,6 +134,8 @@ signals: void loadingStarted(); void loadingFinished(); + void currentItemChanged( const QPersistentModelIndex ¤tIndex ); + public slots: virtual void setCurrentItem( const QModelIndex& index ); diff --git a/src/libtomahawk/playlist/dynamic/widgets/DynamicQmlWidget.cpp b/src/libtomahawk/playlist/dynamic/widgets/DynamicQmlWidget.cpp index ebb455916..bd24bd303 100644 --- a/src/libtomahawk/playlist/dynamic/widgets/DynamicQmlWidget.cpp +++ b/src/libtomahawk/playlist/dynamic/widgets/DynamicQmlWidget.cpp @@ -10,27 +10,35 @@ #include #include #include +#include namespace Tomahawk { DynamicQmlWidget::DynamicQmlWidget( const dynplaylist_ptr& playlist, QWidget* parent ) : QDeclarativeView( parent ) + , QDeclarativeImageProvider( QDeclarativeImageProvider::Pixmap ) , m_playlist( playlist ) { + + engine()->addImageProvider( "albumart", this ); + setResizeMode( QDeclarativeView::SizeRootObjectToView ); - setSource( QUrl( "qrc" RESPATH "qml/ArtistInfoScene.qml" ) ); m_model = new DynamicModel( this ); m_proxyModel = new PlayableProxyModel( this ); m_proxyModel->setSourcePlayableModel( m_model ); - rootContext()->setContextProperty( "dynamicModel", m_model ); m_model->loadPlaylist( m_playlist ); m_model->startOnDemand(); + rootContext()->setContextProperty( "dynamicModel", m_model ); + currentItemChanged( m_model->currentItem() ); + setSource( QUrl( "qrc" RESPATH "qml/StationScene.qml" ) ); + + connect( m_model, SIGNAL( currentItemChanged( QPersistentModelIndex ) ), SLOT( currentItemChanged( QPersistentModelIndex ) ) ); } @@ -73,4 +81,42 @@ DynamicQmlWidget::jumpToCurrentTrack() return false; } +QPixmap DynamicQmlWidget::requestPixmap(const QString &id, QSize *size, const QSize &requestedSize) +{ + qDebug() << "*!*!*!*!*!*!*!*!*!* image requested:" << id; + + // We always can generate it in the requested size + int width = requestedSize.width() > 0 ? requestedSize.width() : 230; + int height = requestedSize.height() > 0 ? requestedSize.height() : 230; + + if( size ) + *size = QSize( width, height ); + + QModelIndex index = m_model->index( id.toInt(), 0, QModelIndex() ); + qDebug() << "got index" << index; + if( index.isValid() ) { + PlayableItem *item = m_model->itemFromIndex( index ); + qDebug() << "got item" << item << item->query(); + qDebug() << "got item" << item << item->query()->coverLoaded(); + if ( !item->album().isNull() && item->album()->coverLoaded() ) { + return item->album()->cover( *size ); + } else if ( !item->artist().isNull() && item->artist()->coverLoaded() ) { + return item->artist()->cover( *size ); + } else if ( !item->query().isNull() && item->query()->coverLoaded() ) { + return item->query()->cover( *size ); + } + } + + // TODO: create default cover art image + QPixmap pixmap( *size ); + pixmap.fill(); + + return pixmap; +} + +void DynamicQmlWidget::currentItemChanged(const QPersistentModelIndex ¤tIndex) +{ + rootContext()->setContextProperty( "currentlyPlayedIndex", m_model->currentItem().row() ); +} + } diff --git a/src/libtomahawk/playlist/dynamic/widgets/DynamicQmlWidget.h b/src/libtomahawk/playlist/dynamic/widgets/DynamicQmlWidget.h index 20d8000cc..f0e8e76fc 100644 --- a/src/libtomahawk/playlist/dynamic/widgets/DynamicQmlWidget.h +++ b/src/libtomahawk/playlist/dynamic/widgets/DynamicQmlWidget.h @@ -23,6 +23,7 @@ #include "Typedefs.h" #include +#include class PlayableProxyModel; @@ -31,7 +32,7 @@ namespace Tomahawk class DynamicModel; -class DynamicQmlWidget : public QDeclarativeView, public Tomahawk::ViewPage +class DynamicQmlWidget : public QDeclarativeView, public Tomahawk::ViewPage, public QDeclarativeImageProvider { Q_OBJECT public: @@ -50,6 +51,11 @@ public: virtual bool jumpToCurrentTrack(); + QPixmap requestPixmap(const QString &id, QSize *size, const QSize &requestedSize); + +private slots: + void currentItemChanged( const QPersistentModelIndex ¤tIndex ); + private: DynamicModel* m_model; PlayableProxyModel* m_proxyModel;