1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-08-30 17:20:26 +02:00

Lots of cleanups

Add button capabilities to header
make use of header in stationview
This commit is contained in:
Michael Zanetti
2012-12-16 04:56:14 +01:00
parent 74d375bc50
commit 8894d16c87
18 changed files with 263 additions and 468 deletions

View File

@@ -0,0 +1,21 @@
import QtQuick 1.1
import tomahawk 1.0
import "tomahawkimports"
// Only to be used together with DeclarativeHeader C++ class
// If you want to use the header in QML, use FlexibleHeader
Item {
anchors.fill: parent
FlexibleHeader {
anchors.fill: parent
icon: iconSource
title: caption
subtitle: description
buttonModel: buttonList
onSearchTextChanged: mainView.setFilterText(searchText)
onCurrentButtonIndexChanged: mainView.viewModeSelected(currentButtonIndex)
}
}

View File

@@ -1,261 +0,0 @@
import QtQuick 1.1
import tomahawk 1.0
import "tomahawkimports"
Item {
id: stationCreator
state: "artist"
property int spacing: width / 10
signal back()
signal next()
Loader {
id: loader
anchors {
left: parent.left
right: parent.right
top: parent.top
bottom: previousButton.top
margins: parent.spacing
}
}
RoundedButton {
id: previousButton
text: "<"
height: spacing
width: height
anchors {
left: parent.left
bottom: parent.bottom;
margins: stationCreator.spacing
}
onClicked: stationCreator.back()
}
RoundedButton {
id: nextButton
text: ">"
height: spacing
width: height
anchors {
right: parent.right
bottom: parent.bottom
margins: stationCreator.spacing
}
onClicked: {
loader.item.createStation()
stationCreator.next()
}
}
states: [
State {
name: "artist"
PropertyChanges { target: loader; sourceComponent: createByArtist }
},
State {
name: "genre"
PropertyChanges { target: loader; sourceComponent: createByGenre }
},
State {
name: "year"
PropertyChanges { target: loader; sourceComponent: createByYear }
}
]
Component {
id: createByArtist
Row {
function createStation() {
mainView.startStationFromArtist(artistInputField.text)
}
anchors.fill: parent
spacing: stationCreator.spacing
Item {
height: parent.height
width: parent.width * 0.7
Text {
id: artistGridLabel
text: "Select an artist..."
anchors { left: parent.left; top: parent.top; right: parent.right }
color: "white"
font.bold: true
}
GridView {
id: gridView
anchors { left: parent.left; top: artistGridLabel.bottom; topMargin: artistGridLabel.height; right: parent.right; bottom: parent.bottom }
model: dummyArtistModel
cellWidth: Math.min(gridView.width / 4 - 1, gridView.height / 2) // -1 to make sure there is space for 4 items even with rounding error
cellHeight: cellWidth
delegate: Item {
height: gridView.cellHeight// * .9
width: height
CoverImage {
artistName: modelData
anchors.fill: parent
showPlayButton: true
onClicked: {
mainView.startStationFromArtist(modelData);
stationCreator.next()
}
}
}
}
}
Item {
height: parent.height
width: parent.width * 0.25
Text {
id: orText
anchors { left: parent.left; right: parent.right;
bottom: artistInputField.top; bottomMargin: height }
text: "...or enter a name:"
color: "white"
font.bold: true
}
InputField {
id: artistInputField
anchors.centerIn: parent
width: parent.width
onAccepted: {
mainView.startStationFromArtist(text)
stationCreator.next()
}
}
}
}
}
Component {
id: createByGenre
Row {
function createStation() {
mainView.startStationFromGenre(genreInputField.text)
}
anchors.fill: parent
spacing: stationCreator.spacing
Item {
height: parent.height
width: parent.width * 0.7
Text {
id: selectGenreText
anchors { left: parent.left; right: parent.right; top: parent.top}
text: "Select a genre..."
color: "white"
font.bold: true
}
TagCloud {
anchors.fill: parent
model: styleModel//generator.styles()
onTagClicked: {
mainView.startStationFromGenre(item)
stationCreator.next()
}
Behavior on opacity {
NumberAnimation { duration: 300 }
}
}
}
Item {
height: parent.height
width: parent.width * 0.25
Text {
id: orText
text: "...or enter your style:"
color: "white"
anchors { left: parent.left; right: parent.right;
bottom: genreInputField.top; bottomMargin: height }
font.bold: true
}
InputField {
id: genreInputField
anchors.centerIn: parent
width: parent.width
onAccepted: {
mainView.startStationFromGenre(text)
stationCreator.next()
}
}
}
}
}
Component {
id: createByYear
Row {
anchors.fill: parent
Item {
height: parent.height
width: parent.width * 0.7
Text {
id: selectYearText
anchors { left: parent.left; right: parent.right; top: parent.top}
text: "Select a decade..."
color: "white"
font.bold: true
}
Row {
id: yearsRow
width: parent.width
anchors.verticalCenter: parent.verticalCenter
spacing: selectYearText.height
function decadeClicked(decade) {
mainView.startStationFromYear(decade)
stationCreator.next()
}
Text { text: "60s"; font.pointSize: 20; color: "white"; MouseArea{ anchors.fill: parent; onClicked: yearsRow.decadeClicked(parent.text)}}
Text { text: "70s"; font.pointSize: 22; color: "white"; MouseArea{ anchors.fill: parent; onClicked: yearsRow.decadeClicked(parent.text)}}
Text { text: "80s"; font.pointSize: 24; color: "white"; MouseArea{ anchors.fill: parent; onClicked: yearsRow.decadeClicked(parent.text)}}
Text { text: "90s"; font.pointSize: 26; color: "white"; MouseArea{ anchors.fill: parent; onClicked: yearsRow.decadeClicked(parent.text)}}
Text { text: "00s"; font.pointSize: 28; color: "white"; MouseArea{ anchors.fill: parent; onClicked: yearsRow.decadeClicked(parent.text)}}
}
}
Item {
height: parent.height
width: parent.width * 0.25
Text {
id: orText
text: "...or specify a year:"
color: "white"
anchors { left: parent.left; right: parent.right;
bottom: yearInputField.top; bottomMargin: height }
font.bold: true
}
InputField {
id: yearInputField
anchors.centerIn: parent
width: parent.width
onAccepted: {
mainView.startStationFromYear(text)
stationCreator.next()
}
}
}
}
}
}

View File

@@ -1,98 +0,0 @@
import QtQuick 1.1
import tomahawk 1.0
import "tomahawkimports"
Rectangle {
id: scene
color: "black"
anchors.fill: parent
state: "list"
ListModel {
id: modeModel
ListElement { label: "By Artist"; image: "../images/artist-placeholder-grid.svg"; creatorContent: "stations/CreateByArtist.qml" }
ListElement { label: "By Genre"; image: "../images/album-placeholder-grid.svg"; creatorContent: "stations/CreateByGenre.qml" }
ListElement { label: "By Year"; image: "image://albumart/foobar"; creatorContent: "year" }
}
VisualItemModel {
id: stationVisualModel
StationCreatorPage1 {
height: scene.height
width: scene.width
model: modeModel
onItemClicked: {
stationCreator.content = modeModel.get(index).creatorContent
stationListView.incrementCurrentIndex()
}
}
StationCreatorPage2 {
id: stationCreator
height: scene.height
width: scene.width
onNext: stationListView.incrementCurrentIndex()
}
StationView {
height: scene.height
width: scene.width
// visible: stationListView.currentIndex == 1
onBackClicked: stationListView.decrementCurrentIndex()
}
}
ListView {
id: stationListView
anchors.fill: parent
contentHeight: scene.height
contentWidth: scene.width
orientation: ListView.Horizontal
model: stationVisualModel
interactive: false
highlightMoveDuration: 300
onHeightChanged: {
contentHeight = scene.height
}
onWidthChanged: {
contentWidth = scene.width
}
}
RoundedButton {
id: backButton
text: "<"
height: defaultFontHeight * 4
width: height
hidden: stationListView.currentIndex == 0
anchors {
left: parent.left
bottom: parent.bottom
margins: defaultFontHeight * 2
}
onClicked: stationListView.decrementCurrentIndex()
}
RoundedButton {
id: nextButton
text: stationListView.currentIndex == 2 ? "+" : ">"
height: defaultFontHeight * 4
//hidden: stationListView.currentIndex == 0 || !rootView.configured // This should work once rootView.configured works
hidden: stationListView.currentIndex != 2
anchors {
right: parent.right
bottom: parent.bottom
margins: defaultFontHeight * 2
}
onClicked: stationListView.incrementCurrentIndex()
}
}

View File

@@ -1,68 +1,127 @@
import QtQuick 1.1
import tomahawk 1.0
import "tomahawkimports"
import "stations"
Rectangle {
id: scene
color: "black"
anchors.fill: parent
state: "list"
Item {
id: root
FlexibleHeader {
id: header
anchors {
left: parent.left
top: parent.top
right: parent.right
}
height: defaultFontHeight * 4
width: parent.width
icon: "../images/station.svg"
title: mainView.title
subtitle: generator.summary
showSearchField: false
showBackButton: stationListView.currentIndex > 0
showNextButton: dynamicModel.rowCount() > 0 && stationListView.currentIndex < 2
showSaveButton: stationListView.currentIndex === 2
signal backClicked()
z: 1 //cover albumcovers that may leave their area
Image {
id: busyIndicator
source: "../images/loading-animation.gif"
anchors.centerIn: parent
height: backButton.height
width: height
visible: mainView.loading
RotationAnimation { target: busyIndicator; from: 360; to: 0; duration: 1500; running: visible; loops: Animation.Infinite }
onBackPressed: stationListView.decrementCurrentIndex()
onNextPressed: stationListView.incrementCurrentIndex()
onSavePressed: print("should save station now")
}
CoverFlip {
id: coverView
anchors.fill: parent
ListModel {
id: modeModel
ListElement { label: "By Artist"; image: "../../images/artist-placeholder-grid.svg"; creatorContent: "stations/CreateByArtist.qml" }
ListElement { label: "By Genre"; image: "../../images/album-placeholder-grid.svg"; creatorContent: "stations/CreateByGenre.qml" }
ListElement { label: "By Year"; image: "image://albumart/foobar"; creatorContent: "year" }
}
VisualItemModel {
id: stationVisualModel
StationCreatorPage1 {
height: scene.height - header.height
width: scene.width
model: modeModel
onItemClicked: {
stationCreator.content = modeModel.get(index).creatorContent
stationListView.incrementCurrentIndex()
}
}
StationCreatorPage2 {
id: stationCreator
height: stationListView.height
width: stationListView.width
onNext: stationListView.incrementCurrentIndex()
}
Item {
id: stationItem
height: stationListView.height
width: stationListView.width
Image {
id: busyIndicator
source: "../images/advanced-settings.svg"
anchors.centerIn: parent
height: defaultFontHeight * 4
width: height
visible: mainView.loading
RotationAnimation { target: busyIndicator; from: 360; to: 0; duration: 1500; running: visible; loops: Animation.Infinite }
}
CoverFlip {
id: coverView
anchors.fill: parent
interactive: false
backgroundColor: scene.color
model: dynamicModel
currentIndex: currentlyPlayedIndex
onItemPlayPauseClicked: {
mainView.playItem(index)
}
onItemClicked: {
mainView.playItem(index)
}
}
}
}
ListView {
id: stationListView
anchors {
left: parent.left
top: header.bottom
right: parent.right
bottom: parent.bottom
}
contentHeight: height
contentWidth: width
orientation: ListView.Horizontal
model: stationVisualModel
interactive: false
highlightMoveDuration: 300
backgroundColor: scene.color
model: dynamicModel
currentIndex: currentlyPlayedIndex
onItemPlayPauseClicked: {
mainView.playItem(index)
onHeightChanged: {
contentHeight = scene.height
}
onItemClicked: {
mainView.playItem(index)
onWidthChanged: {
contentWidth = scene.width
}
}
Item {
anchors { top: parent.top; left: parent.left; bottom: parent.bottom }
anchors.margins: titleText.height * 3
width: scene.width / 2
Column {
anchors { left: parent.left; top: parent.top; right: parent.right }
Text {
id: titleText
color: "white"
font.pointSize: 18
width: parent.width
elide: Text.ElideRight
text: mainView.title
}
Text {
color: "white"
font.pointSize: 14
font.bold: true
width: parent.width
elide: Text.ElideRight
opacity: .8
text: generator.summary
}
}
}
}

View File

@@ -1,6 +1,6 @@
import QtQuick 1.1
import tomahawk 1.0
import "tomahawkimports"
import "../tomahawkimports"
Item {
@@ -10,15 +10,6 @@ Item {
signal itemClicked(int index)
HeaderLabel {
text: "Listen to radio..."
anchors {
left: parent.left
top: parent.top
margins: defaultFontHeight * 2
}
}
GridView {
id: gridView
anchors.centerIn: parent

View File

@@ -1,6 +1,6 @@
import QtQuick 1.1
import tomahawk 1.0
import "tomahawkimports"
import "../tomahawkimports"
Item {
id: root

View File

@@ -1,6 +1,5 @@
import QtQuick 1.1
import tomahawk 1.0
import "tomahawkimports"
PathView {
id: coverView

View File

@@ -3,25 +3,60 @@ import tomahawk 1.0
Rectangle {
id: root
anchors.fill: parent
// The icon
property alias icon: iconImage.source
// The title
property alias title: titleItem.titleText
// The subtitle/description
property alias subtitle: subtitleText.text
// The model for the ToggleViewButtons.
// "modelData" role name holds the iconSource
// => You can use a QStringList or StandardListModel here
property alias buttonModel: toggleViewButtons.model
// The index of the currently selected item
property alias currentButtonIndex: toggleViewButtons.currentIndex
// Should we show the searchfield?
property bool showSearchField: true
// The SearchFields text
property alias searchText: searchField.text
property bool showBackButton: false
property bool showNextButton: false
property bool showSaveButton: false
// Layout spacing
property int spacing: defaultFontHeight / 2
signal backPressed()
signal nextPressed()
signal savePressed()
gradient: Gradient {
GradientStop { position: 0.0; color: "#615858" }
GradientStop { position: 1.0; color: "#231F1F" }
}
Row {
anchors.fill: parent
id: leftRow
anchors {
left: parent.left
top: parent.top
bottom: parent.bottom
right: rightRow.left
}
anchors.margins: root.spacing
spacing: root.spacing
Image {
id: iconImage
source: iconSource
height: parent.height * 0.8
width: height
anchors.verticalCenter: parent.verticalCenter
@@ -29,7 +64,7 @@ Rectangle {
Column {
height: parent.height
width: parent.width - iconImage.width - toggleViewButtons.width - searchField.width - parent.spacing * 5
width: parent.width - iconImage.width - parent.spacing
Item {
id: titleItem
@@ -37,11 +72,11 @@ Rectangle {
width: parent.width
clip: true
property string titleText: caption
property string titleText
onTitleTextChanged: {
if(captionText1.text.length > 0) {
captionText2.text = caption;
captionText2.text = titleText;
renewTitleAnimation.start();
} else {
captionText1.text = titleText;
@@ -88,7 +123,7 @@ Rectangle {
}
Text {
text: description
id: subtitleText
color: "white"
font.pointSize: defaultFontSize + 1
width: parent.width
@@ -96,27 +131,52 @@ Rectangle {
}
}
}
Row {
id: rightRow
anchors {
top: parent.top
right: parent.right
bottom: parent.bottom
margins: root.spacing
}
width: childrenRect.width
spacing: root.spacing
layoutDirection: Qt.RightToLeft
RoundedButton {
height: parent.height * 0.8
anchors.verticalCenter: parent.verticalCenter
text: "+"
visible: root.showSaveButton
onClicked: root.saveClicked()
}
RoundedButton {
height: parent.height * 0.8
anchors.verticalCenter: parent.verticalCenter
text: ">"
visible: root.showNextButton
onClicked: root.nextPressed();
}
RoundedButton {
anchors.verticalCenter: parent.verticalCenter
height: parent.height * 0.8
text: "<"
visible: root.showBackButton
onClicked: root.backPressed();
}
InputField {
id: searchField
visible: root.showSearchField
anchors.verticalCenter: parent.verticalCenter
}
ToggleViewButtons {
id: toggleViewButtons
anchors.verticalCenter: parent.verticalCenter
height: defaultFontHeight * 1.5
model: toggleViewButtonModel
onCurrentIndexChanged: mainView.viewModeSelected(currentIndex)
}
SearchField {
id: searchField
opacity: root.showSearchField ? 1 : 0
anchors {
right: parent.right
verticalCenter: parent.verticalCenter
rightMargin: root.spacing
}
onTextChanged: mainView.setFilterText(text)
}
}
}

View File

@@ -139,25 +139,23 @@
<file>data/images/account-none.svg</file>
<file>data/images/green-dot.svg</file>
<file>data/images/exfm.png</file>
<file>data/qml/StationScene.qml</file>
<file>data/qml/StationConfig.qml</file>
<file>data/qml/StationView.qml</file>
<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>
<file>data/qml/tomahawkimports/RoundedButton.qml</file>
<file>data/qml/StationCreator.qml</file>
<file>data/qml/StationCreatorPage1.qml</file>
<file>data/qml/GridView.qml</file>
<file>data/qml/StationCreatorPage2.qml</file>
<file>data/qml/stations/CreateByArtist.qml</file>
<file>data/qml/tomahawkimports/CoverImage.qml</file>
<file>data/qml/tomahawkimports/ArtistView.qml</file>
<file>data/qml/tomahawkimports/HeaderLabel.qml</file>
<file>data/qml/stations/CreateByGenre.qml</file>
<file>data/qml/tomahawkimports/TagCloud.qml</file>
<file>data/qml/tomahawkimports/ScrollBar.qml</file>
<file>data/qml/tomahawkimports/InputField.qml</file>
<file>data/qml/tomahawkimports/Button.qml</file>
<file>data/qml/tomahawkimports/DoubleSlider.qml</file>
<file>data/qml/tomahawkimports/RoundedButton.qml</file>
<file>data/qml/tomahawkimports/CoverFlip.qml</file>
<file>data/qml/StationView.qml</file>
<file>data/qml/stations/StationCreatorPage1.qml</file>
<file>data/qml/stations/StationCreatorPage2.qml</file>
<file>data/qml/stations/CreateByArtist.qml</file>
<file>data/qml/stations/StationConfig.qml</file>
<file>data/qml/QmlGridView.qml</file>
<file>data/qml/stations/CreateByGenre.qml</file>
<file>data/images/soundcloud.svg</file>
<file>data/images/resolver-default.svg</file>
<file>data/images/spotify-sourceicon.svg</file>
@@ -168,5 +166,6 @@
<file>data/images/ok.svg</file>
<file>data/qml/tomahawkimports/FlexibleHeader.qml</file>
<file>data/qml/tomahawkimports/ToggleViewButtons.qml</file>
<file>data/qml/DeclarativeHeader.qml</file>
</qresource>
</RCC>

View File

@@ -63,7 +63,7 @@ QmlGridView::QmlGridView(QWidget *parent) : DeclarativeView(parent)
rootContext()->setContextProperty( "mainModel", m_proxyModel );
setSource( QUrl( "qrc" RESPATH "qml/GridView.qml" ) );
setSource( QUrl( "qrc" RESPATH "qml/QmlGridView.qml" ) );
}
QmlGridView::~QmlGridView()

View File

@@ -119,6 +119,7 @@ signals:
void error( const QString& title, const QString& body);
void generated( const QList< Tomahawk::query_ptr>& queries );
void nextTrackGenerated( const Tomahawk::query_ptr& track );
void summaryChanged();
protected:
QString m_type;

View File

@@ -45,12 +45,14 @@ DynamicQmlWidget::DynamicQmlWidget( const dynplaylist_ptr& playlist, QWidget* pa
rootContext()->setContextProperty( "dynamicModel", m_proxyModel );
rootContext()->setContextProperty( "artistChartsModel", m_artistChartsModel );
rootContext()->setContextProperty( "generator", m_playlist->generator().data() );
rootContext()->setContextProperty( "currentlyPlayedIndex", QVariant::fromValue( 0 ) );
setSource( QUrl( "qrc" RESPATH "qml/StationScene.qml" ) );
setSource( QUrl( "qrc" RESPATH "qml/StationView.qml" ) );
connect( m_model, SIGNAL( currentItemChanged(QPersistentModelIndex)), SLOT( currentIndexChanged( QPersistentModelIndex ) ) );
connect( m_model, SIGNAL( loadingStarted() ), SIGNAL(loadingChanged() ) );
connect( m_model, SIGNAL( loadingFinished() ), SIGNAL(loadingChanged() ) );
connect( m_model, SIGNAL( changed() ), SIGNAL( titleChanged() ) );
connect( m_playlist->generator().data(), SIGNAL( generated( QList<Tomahawk::query_ptr> ) ), this, SLOT( tracksGenerated( QList<Tomahawk::query_ptr> ) ) );
connect( m_playlist->generator().data(), SIGNAL( nextTrackGenerated( Tomahawk::query_ptr ) ), this, SLOT( nextTrackGenerated( Tomahawk::query_ptr ) ) );
connect( m_playlist.data(), SIGNAL( dynamicRevisionLoaded( Tomahawk::DynamicPlaylistRevision ) ), this, SLOT( onRevisionLoaded( Tomahawk::DynamicPlaylistRevision ) ) );

View File

@@ -37,7 +37,7 @@ class DynamicQmlWidget : public DeclarativeView, public Tomahawk::ViewPage
{
Q_OBJECT
Q_PROPERTY(QString title READ title)
Q_PROPERTY(QString title READ title NOTIFY titleChanged)
Q_PROPERTY(bool loading READ loading NOTIFY loadingChanged)
Q_PROPERTY(bool configured READ configured NOTIFY configuredChanged)
@@ -66,6 +66,7 @@ public:
signals:
void loadingChanged();
void configuredChanged();
void titleChanged();
public slots:
void playItem(int index);

View File

@@ -11,12 +11,19 @@ DeclarativeHeader::DeclarativeHeader(QWidget *parent)
{
QStringList buttonList;
buttonList << "view-toggle-icon-artist" << "view-toggle-icon-list" << "view-toggle-icon-grid";
rootContext()->setContextProperty("toggleViewButtonModel", buttonList );
buttonList << "view-toggle-icon-artist"
<< "view-toggle-icon-list"
<< "view-toggle-icon-grid";
rootContext()->setContextProperty("buttonList", buttonList );
setSource( QUrl( "qrc" RESPATH "qml/tomahawkimports/FlexibleHeader.qml" ) );
setIconSource(QString());
setCaption(QString());
setDescription(QString());
connect(&m_filterTimer, SIGNAL(timeout()), SLOT(applyFilter()));
setSource( QUrl( "qrc" RESPATH "qml/DeclarativeHeader.qml" ) );
}
void DeclarativeHeader::setIconSource(const QString &iconSource)

View File

@@ -14,3 +14,13 @@ SearchFieldQmlProxy::SearchFieldQmlProxy(QGraphicsItem *parent) :
connect(m_searchField, SIGNAL(returnPressed()), SIGNAL(returnPressed()));
}
QString SearchFieldQmlProxy::text() const
{
return m_searchField->text();
}
void SearchFieldQmlProxy::setText(const QString &text)
{
m_searchField->setText(text);
}

View File

@@ -8,9 +8,13 @@ class QSearchField;
class SearchFieldQmlProxy: public QGraphicsProxyWidget
{
Q_OBJECT
Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged)
public:
SearchFieldQmlProxy(QGraphicsItem* parent = 0);
QString text() const;
void setText(const QString &text);
signals:
void textChanged(const QString &text);
void editingFinished();