1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-08-31 09:32:03 +02:00

some more work on stations

This commit is contained in:
Michael Zanetti
2012-11-24 23:38:15 +01:00
parent 4b23fe2fe0
commit 8462a47985
9 changed files with 207 additions and 141 deletions

82
data/qml/CoverFlip.qml Normal file
View File

@@ -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 }
}
}

View File

@@ -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

View File

@@ -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
// }
}
}

View File

@@ -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 }

View File

@@ -171,5 +171,6 @@
<file>data/qml/tomahawkimports/InputField.qml</file>
<file>data/qml/tomahawkimports/Button.qml</file>
<file>data/qml/tomahawkimports/DoubleSlider.qml</file>
<file>data/qml/CoverFlip.qml</file>
</qresource>
</RCC>

View File

@@ -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();

View File

@@ -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 );
}

View File

@@ -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 &currentIndex )
{
rootContext()->setContextProperty( "currentlyPlayedIndex", m_proxyModel->mapFromSource( currentIndex ).row() );

View File

@@ -54,6 +54,10 @@ public:
playlist_ptr playlist() const;
public slots:
void playItem(int index);
void pause();
private slots:
void currentItemChanged( const QPersistentModelIndex &currentIndex );
void tracksGenerated( const QList< Tomahawk::query_ptr>& queries );