1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-08-10 16:14:40 +02:00

some more work on stations merged

This commit is contained in:
Michael Zanetti
2013-05-19 00:39:29 +02:00
parent 2e3785f92b
commit fcc6f5c966
15 changed files with 396 additions and 123 deletions

View File

@@ -11,6 +11,7 @@ BusyIndicator {
anchors.horizontalCenterOffset: 200
height: 200
width: 200
count: 11
}
Image {

View File

@@ -19,23 +19,42 @@ Rectangle {
width: parent.width
icon: "../images/station.svg"
title: mainView.title
subtitle: generator.summary
subtitle: ""//generator.summary
showSearchField: false
showBackButton: stationListView.currentIndex > 0
showNextButton: stationListView.currentIndex == 2
showNextButton: !mainView.configured && stationListView.currentIndex == 2
nextButtonText: "Save"
backButtonText: mainView.configured ? "Configure" : "Back"
z: 1 //cover albumcovers that may leave their area
onBackPressed: stationListView.decrementCurrentIndex()
onNextPressed: stationListView.incrementCurrentIndex()
onBackPressed: {
if(mainView.configured) {
return;
}
inputBubble.opacity = 0
stationListView.decrementCurrentIndex()
if(stationListView.currentIndex == 1) {
subtitle = modeModel.get(stationCreator.modeIndex).headerSubtitle + "..."
}
if(stationListView.currentIndex == 0) {
subtitle = ""
}
}
// In our case the next button is the save button
onNextPressed: {
inputBubble.opacity = 1
saveNameInput.forceActiveFocus();
}
}
ListModel {
id: modeModel
ListElement { label: "By Artist"; image: "../../images/station-artist.svg"; creatorContent: "stations/CreateByArtist.qml" }
ListElement { label: "By Genre"; image: "../../images/station-genre.svg"; creatorContent: "stations/CreateByGenre.qml" }
ListElement { label: "By Year"; image: "../../images/station-year.svg"; creatorContent: "year" }
ListElement { label: "By Artist"; image: "../../images/station-artist.svg"; creatorContent: "stations/CreateByArtist.qml"; headerSubtitle: "by" }
ListElement { label: "By Genre"; image: "../../images/station-genre.svg"; creatorContent: "stations/CreateByGenre.qml"; headerSubtitle: "like" }
ListElement { label: "By Year"; image: "../../images/station-year.svg"; creatorContent: "stations/CreateByYear.qml"; headerSubtitle: "from" }
}
VisualItemModel {
@@ -47,8 +66,9 @@ Rectangle {
model: modeModel
onItemClicked: {
stationCreator.content = modeModel.get(index).creatorContent
stationCreator.modeIndex = index
stationListView.incrementCurrentIndex()
header.subtitle = modeModel.get(index).headerSubtitle + "..."
}
}
@@ -57,84 +77,35 @@ Rectangle {
height: stationListView.height
width: stationListView.width
onNext: stationListView.incrementCurrentIndex()
property int modeIndex
content: modeModel.get(modeIndex).creatorContent
onNext: {
stationListView.incrementCurrentIndex()
header.subtitle = modeModel.get(modeIndex).headerSubtitle + " " + text
}
}
Item {
StationItem {
id: stationItem
height: stationListView.height
width: stationListView.width
CoverFlip {
id: coverView
anchors.right: parent.right
anchors.top: parent.top
height: parent.height
width: parent.width
interactive: false
backgroundColor: scene.color
model: dynamicModel
currentIndex: currentlyPlayedIndex
onItemPlayPauseClicked: {
mainView.playItem(index)
}
onItemClicked: {
mainView.playItem(index)
}
states: [
State {
name: "empty"; when: mainView.loading
PropertyChanges {
target: coverView
anchors.rightMargin: -coverView.width
anchors.topMargin: - coverView.height
scale: 0
}
}
]
transitions: [
Transition {
from: "empty"
to: "*"
NumberAnimation {
properties: "anchors.topMargin,anchors.rightMargin,scale"
duration: 1000
easing.type: Easing.OutQuad
}
}
]
// Behavior on anchors.topMargin {
// NumberAnimation { duration: 500 }
// }
// Behavior on anchors.rightMargin {
// NumberAnimation { duration: 500 }
// }
// Behavior on scale {
// NumberAnimation { duration: 500 }
// }
}
BusyIndicator {
id: busyIndicator
anchors.centerIn: parent
height: defaultFontHeight * 4
width: height
opacity: mainView.loading ? 1 : 0
running: mainView.loading
}
}
}
VisualItemModel {
id: configuredStationVisualModel
StationItem {
id: cfgstationItem
height: stationListView.height
width: stationListView.width
}
}
ListView {
id: stationListView
anchors {
@@ -147,7 +118,7 @@ Rectangle {
contentHeight: height
contentWidth: width
orientation: ListView.Horizontal
model: stationVisualModel
//model: mainView.configured ? configuredStationVisualModel : stationVisualModel
interactive: false
highlightMoveDuration: 300
@@ -157,6 +128,62 @@ Rectangle {
onWidthChanged: {
contentWidth = scene.width
}
Component.onCompleted: {
model = mainView.configured ? configuredStationVisualModel : stationVisualModel
}
onModelChanged: print("ccccccccccccc", mainView.configured)
}
Rectangle {
id: inputBubble
color: "black"
border.width: 2
border.color: "white"
height: defaultFontHeight * 3
width: height * 6
radius: defaultFontHeight / 2
anchors.top: header.bottom
anchors.right: parent.right
anchors.rightMargin: defaultFontHeight / 2
anchors.topMargin: -defaultFontHeight / 2
z: 2
opacity: 0
Behavior on opacity {
NumberAnimation { duration: 200 }
}
Row {
anchors.centerIn: parent
width: parent.width - defaultFontHeight
spacing: defaultFontHeight / 2
function saveStation(name) {
mainView.title = name
inputBubble.opacity = 0
header.showNextButton = false
header.backButtonText = "Configure"
}
Text {
id: nameText
color: "white"
text: "Name:"
anchors.verticalCenter: parent.verticalCenter
}
InputField {
id: saveNameInput
width: parent.width - nameText.width - saveOkButton.width - parent.spacing * 2
placeholderText: "Station"
onAccepted: parent.saveStation(text);
}
PushButton {
id: saveOkButton
text: "OK"
onClicked: parent.saveStation(saveNameInput.text)
}
}
}
}

View File

@@ -6,11 +6,11 @@ Item {
id: root
anchors.fill: parent
signal done()
signal done(string text)
function createStation(artist) {
mainView.startStationFromArtist(artist)
root.done()
root.done(artist)
}
Column {

View File

@@ -6,11 +6,11 @@ Item {
id: root
anchors.fill: parent
signal done()
signal done(string text)
function createStation(genre) {
mainView.startStationFromGenre(genre)
root.done()
root.done(genre)
}
ListModel {

View File

@@ -0,0 +1,79 @@
import QtQuick 1.1
import tomahawk 1.0
import "../tomahawkimports"
Item {
id: root
anchors.fill: parent
signal done(string text)
function createStation(artist) {
mainView.startStationFromArtist(artist)
root.done(artist)
}
Column {
id: upperColumn
anchors.horizontalCenter: parent.horizontalCenter
height: parent.height
width: defaultFontHeight * 30
anchors.bottomMargin: defaultFontHeight
spacing: defaultFontHeight
HeaderLabel {
id: headerText
text: "Create station by year..."
}
Row {
height: artistInputField.height
width: parent.width
spacing: defaultFontHeight * 0.5
InputField {
id: artistInputField
width: parent.width - createFromInputButton.width - parent.spacing
onAccepted: createStation(text)
}
PushButton {
id: createFromInputButton
text: "Go!"
enabled: artistInputField.text.length > 2
onClicked: createStation(artistInputField.text)
}
}
// Item {
// height: parent.height - headerText.height - artistInputField.height - parent.spacing * 3
// width: parent.width
// ArtistView {
// id: artistView
// height: parent.height
// width: parent.width
// model: artistChartsModel
// clip: true
// delegateHeight: defaultFontHeight * 6
// onItemClicked: {
// createStation(artistChartsModel.itemFromIndex(index).artistName);
// }
// }
// ScrollBar {
// listView: artistView
// }
// }
DoubleSlider {
width: parent.width
height: defaultFontHeight * 2
min: 1960
max: new Date().getFullYear()
lowerSliderPos: 1990
upperSliderPos: 2010
minMaxLabelsVisible: false
}
}
}

View File

@@ -8,7 +8,7 @@ Item {
property int margins: defaultFontHeight * 2
property alias content: contentLoader.source
signal next()
signal next(string text)
Loader {
id: contentLoader
@@ -19,7 +19,7 @@ Item {
Connections {
target: contentLoader.item
onDone: root.next()
onDone: root.next(text)
}
}

View File

@@ -0,0 +1,73 @@
import QtQuick 1.1
import tomahawk 1.0
import "../tomahawkimports"
Item {
id: stationItem
CoverFlip {
id: coverView
anchors.right: parent.right
anchors.top: parent.top
height: parent.height
width: parent.width
interactive: false
backgroundColor: scene.color
model: dynamicModel
currentIndex: currentlyPlayedIndex
onItemPlayPauseClicked: {
mainView.playItem(index)
}
onItemClicked: {
mainView.playItem(index)
}
states: [
State {
name: "empty"; when: mainView.loading
PropertyChanges {
target: coverView
anchors.rightMargin: -coverView.width
anchors.topMargin: - coverView.height
scale: 0
}
}
]
transitions: [
Transition {
from: "empty"
to: "*"
NumberAnimation {
properties: "anchors.topMargin,anchors.rightMargin,scale"
duration: 1000
easing.type: Easing.OutQuad
}
}
]
// Behavior on anchors.topMargin {
// NumberAnimation { duration: 500 }
// }
// Behavior on anchors.rightMargin {
// NumberAnimation { duration: 500 }
// }
// Behavior on scale {
// NumberAnimation { duration: 500 }
// }
}
BusyIndicator {
id: busyIndicator
anchors.centerIn: parent
height: defaultFontHeight * 4
width: height
opacity: mainView.loading ? 1 : 0
running: mainView.loading
}
}

View File

@@ -49,8 +49,6 @@ PathView {
right: parent.right
}
backgroundColor: coverView.backgroundColor
showLabels: true
showMirror: true
artistName: model.artistName

View File

@@ -25,9 +25,6 @@ Item {
// The border width for the cover image
property int borderWidth: 2
// needed to adjust the shadow
property color backgroundColor: "black"
// sets the brightness for the item and its mirror (1: brightest, 0: darkest)
property double itemBrightness: 1
property double mirrorBrightness: .5
@@ -55,7 +52,7 @@ Item {
Rectangle {
id: itemShadow
color: backgroundColor
color: "black"
anchors.fill: parent
//opacity: 1 - itemBrightness

View File

@@ -2,8 +2,6 @@ import QtQuick 1.1
Item {
id: root
width: 500
height: 10
property int min: 0
property int max: 100
@@ -16,71 +14,144 @@ Item {
/** Should the floating label indicating the current position be shown? */
property bool showFloatingLabel: true
property bool minMaxLabelsVisible: true
property int lowerSliderPos: 25
property int upperSliderPos: 75
onUpperSliderPosChanged: print("fooooooooo", upperSliderPos)
signal valueChanged()
QtObject {
id: priv
property int steps: root.max - root.min + 1
property int sliderHeight: root.height
property int sliderWidth: root.height / 2
}
Row {
anchors.fill: parent
anchors.topMargin: defaultFontHeight * 1.2
anchors.bottomMargin: defaultFontHeight * 1.2
spacing: 10
Text {
id: minText
text: root.minLabel.length > 0 ? root.minLabel : min
color: "white"
visible: root.minMaxLabelsVisible
}
Item {
id: sliderRect
height: root.height
width: parent.width - minText.width - maxText.width - parent.spacing * 2
property int maxWidth: parent.width - (minText.visible ? minText.width : 0) - (maxText.visible ? maxText.width : 0) - parent.spacing * 2
width: maxWidth - (maxWidth % priv.steps)
anchors.horizontalCenter: parent.horizontalCenter
function sliderPosToValue( sliderPos ) {
var percent = sliderPos * 100 / (sliderRect.width - lowerSlider.width);
return Math.floor(percent * (root.max - root.min) / 100) + root.min
var percent = sliderPos * 100 / (sliderRect.width - priv.sliderWidth/2);
return Math.floor(percent * (priv.steps-1) / 100) + root.min
}
function valueToSloderPos( value ) {
var percent = (value - root.min) * 100 / (root.max - root.min)
return percent * (sliderRect.width - lowerSlider.width) / 100
var percent = (value - root.min) * 100 / (priv.steps-1)
return percent * (sliderRect.width - priv.sliderWidth/2) / 100
}
Rectangle {
id: sliderBase
height: root.height / 5
width: parent.width
height: root.height / 1.5
width: parent.width + defaultFontHeight * 1.5
color: "white"
radius: height / 2
anchors.centerIn: parent
gradient: Gradient {
GradientStop { position: 0.0; color: "#ffffffff" }
GradientStop { position: 1.0; color: "#aaffffff" }
}
Rectangle {
anchors.fill: sliderBase
anchors.leftMargin: lowerSlider.x + priv.sliderWidth
anchors.rightMargin: sliderBase.width - upperSlider.x - priv.sliderWidth
gradient: Gradient {
GradientStop { position: 0.0; color: "#aa962c26" }
GradientStop { position: 1.0; color: "#962c26" }
}
}
Row {
id: stepRow
anchors.fill: parent
anchors.leftMargin: defaultFontHeight - lineWidth/2
anchors.rightMargin: defaultFontHeight - lineWidth/2
property int stepCount: root.max - root.min + 1
property int lineHeight: height
property int lineWidth: lineHeight / 15
spacing: (width - (stepCount * lineWidth)) / stepCount
Repeater {
model: stepRow.stepCount
Rectangle {
id: marker
height: stepRow.lineHeight * (isHighlight ? 1.2 : 1)
width: stepRow.lineWidth
color: "black"
property bool isHighlight: index % 10 === 0
gradient: Gradient {
GradientStop { position: 0.0; color: marker.isHighlight ? "white" : "black" }
GradientStop { position: 1.0; color: marker.isHighlight ? "#aaffffff" : "black" }
}
Text {
text: root.min + index
visible: marker.isHighlight
anchors.horizontalCenter: marker.horizontalCenter
anchors.top: marker.bottom
anchors.topMargin: defaultFontHeight / 2
color: "white"
}
}
}
}
}
Rectangle {
id: lowerSlider
height: root.height
width: height
height: priv.sliderHeight
width: priv.sliderWidth
anchors.top: root.top
radius: height/2
radius: height/4
border.color: "black"
border.width: 2
x: sliderRect.valueToSloderPos(root.lowerSliderPos)
x: sliderRect.valueToSloderPos(root.lowerSliderPos) - priv.sliderWidth/2
Rectangle {
id: lowerFloatingRect
color: "white"
anchors.bottom: lowerSlider.top
anchors.bottomMargin: 10
visible: root.showFloatingLabel && lowerSliderMouseArea.pressed
// visible: root.showFloatingLabel && lowerSliderMouseArea.pressed
width: lowerFloatingText.width * 1.2
height: lowerFloatingText.height + height * 1.2
x: -(width - lowerSlider.width) / 2
radius: height / 4
x: -(width - priv.sliderWidth) / 2
radius: height / 8
Text {
id: lowerFloatingText
anchors.centerIn: parent
text: sliderRect.sliderPosToValue(lowerSlider.x)
text: sliderRect.sliderPosToValue(lowerSlider.x + priv.sliderWidth/2)
}
}
}
@@ -89,10 +160,10 @@ Item {
anchors.fill: lowerSlider
drag.target: lowerSlider
drag.axis: "XAxis"
drag.minimumX: 0
drag.maximumX: upperSlider.x - lowerSlider.width
drag.minimumX: -priv.sliderWidth / 2
drag.maximumX: upperSlider.x - priv.sliderWidth
onReleased: {
root.lowerSliderPos = sliderRect.sliderPosToValue( lowerSlider.x );
root.lowerSliderPos = sliderRect.sliderPosToValue( lowerSlider.x + priv.sliderWidth/2 );
root.valueChanged();
}
}
@@ -100,9 +171,9 @@ Item {
Rectangle {
id: upperSlider
height: root.height
width: height
width: height / 2
anchors.top: root.top
radius: height/2
radius: height / 4
border.color: "black"
border.width: 2
x: sliderRect.valueToSloderPos(root.upperSliderPos)
@@ -111,16 +182,16 @@ Item {
color: "white"
anchors.bottom: upperSlider.top
anchors.bottomMargin: 10
visible: root.showFloatingLabel && upperSliderMouseArea.pressed
// visible: root.showFloatingLabel && upperSliderMouseArea.pressed
width: upperFloatingText.width * 1.2
height: upperFloatingText.height + height * 1.2
radius: height / 4
x: -(width - upperSlider.width) / 2
x: -(width - priv.sliderWidth) / 2
Text {
id: upperFloatingText
anchors.centerIn: parent
text: sliderRect.sliderPosToValue(upperSlider.x)
text: sliderRect.sliderPosToValue(upperSlider.x + priv.sliderWidth/2)
}
}
@@ -131,14 +202,16 @@ Item {
onClicked: print("button pressed")
drag.target: upperSlider
drag.axis: "XAxis"
drag.minimumX: lowerSlider.x + lowerSlider.width
drag.maximumX: parent.width - upperSlider.width
drag.minimumX: lowerSlider.x + priv.sliderWidth
drag.maximumX: parent.width - priv.sliderWidth
onReleased: {
root.upperSliderPos = sliderRect.sliderPosToValue( upperSlider.x );
root.upperSliderPos = sliderRect.sliderPosToValue( upperSlider.x + priv.sliderWidth/2 );
root.valueChanged();
}
}
}
@@ -146,6 +219,7 @@ Item {
id: maxText
text: root.maxLabel.length > 0 ? root.maxLabel : max
color: "white"
visible: root.minMaxLabelsVisible
}
}
}

View File

@@ -17,6 +17,12 @@ Rectangle {
property int spacing: defaultFontHeight * 0.2
signal accepted( string text )
onFocusChanged: {
if(focus) {
textInput.forceActiveFocus();
}
}
Image {
id: searchIcon
anchors {

View File

@@ -16,7 +16,7 @@ Item {
Flow {
anchors.centerIn: parent
width: parent.width
spacing: 3
spacing: defaultFontSize
Repeater {
id: cloudRepeater
@@ -26,7 +26,7 @@ Item {
id: cloudItem
width: delegateText.width * 1.1
height: delegateText.height
property double itemScale: Math.random() + .3
property double itemScale: tagCloud.randomNumber(0.5, 1.2)
scale: itemScale
Text {
id: delegateText
@@ -35,7 +35,7 @@ Item {
text: modelData
font.pointSize: 16
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: tagCloud.randomNumber(0, 15)
//anchors.verticalCenterOffset: tagCloud.randomNumber(0, 15)
states: [
State {

View File

@@ -103,9 +103,11 @@
<file>data/qml/tomahawkimports/CoverFlip.qml</file>
<file>data/qml/tomahawkimports/BusyIndicator.qml</file>
<file>data/qml/StationView.qml</file>
<file>data/qml/stations/StationItem.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/CreateByYear.qml</file>
<file>data/qml/stations/StationConfig.qml</file>
<file>data/qml/QmlGridView.qml</file>
<file>data/qml/stations/CreateByGenre.qml</file>

View File

@@ -82,7 +82,22 @@ DynamicQmlWidget::playlistInterface() const
QString
DynamicQmlWidget::title() const
{
return m_model->title();
if ( !m_playlist->title().isEmpty() ) {
return m_playlist->title();
}
return "Listen to radio...";
}
void
DynamicQmlWidget::setTitle(const QString &title)
{
m_model->setTitle( title );
m_playlist->setTitle( title );
m_model->playlist()->setTitle( title );
m_playlist->createNewRevision( uuid(), m_playlist->currentrevision(), m_playlist->type(), m_playlist->generator()->controls() );
m_playlist->reportCreated( m_playlist );
emit titleChanged();
}

View File

@@ -37,7 +37,7 @@ class DynamicQmlWidget : public DeclarativeView, public Tomahawk::ViewPage
{
Q_OBJECT
Q_PROPERTY(QString title READ title NOTIFY titleChanged)
Q_PROPERTY(QString title READ title WRITE setTitle NOTIFY titleChanged)
Q_PROPERTY(bool loading READ loading NOTIFY loadingChanged)
Q_PROPERTY(bool configured READ configured NOTIFY configuredChanged)
@@ -49,6 +49,7 @@ public:
virtual Tomahawk::playlistinterface_ptr playlistInterface() const;
virtual QString title() const;
virtual void setTitle(const QString &title);
virtual QString description() const;
virtual QString iconSource() const;