Commit 82b9f4d0 authored by Leander Schulten's avatar Leander Schulten

WIP: Added InfoScreen with InfoScreenPropertiesView where you can manage the...

WIP: Added InfoScreen with InfoScreenPropertiesView where you can manage the offers. Change the Spotify objects to make them accessible in QML
parent 6b724665
Pipeline #148678 passed with stage
in 1 minute and 17 seconds
......@@ -127,6 +127,11 @@ int main(int argc, char *argv[])
qRegisterMetaType<Modules::PropertiesVector*>("PropertiesVector*");
qRegisterMetaType<Driver::DMXQMLValue*>("DMXQMLValue*");
qRegisterMetaType<DMX::DMXChannelFilter*>("DMXChannelFilter*");
qRegisterMetaType<Spotify::Objects::TrackObject_full*>("Spotify::Objects::TrackObject_full*");
qRegisterMetaType<Spotify::Objects::CurrentPlayingObject*>("Spotify::Objects::CurrentPlayingObject*");
qRegisterMetaType<Spotify::Objects::UserObject*>("Spotify::Objects::UserObject*");
qRegisterMetaType<Spotify::Objects::ImageObject>("Spotify::Objects::ImageObject");
qRegisterMetaType<Spotify::Objects::ImageObject*>("Spotify::Objects::ImageObject*");
updater.checkForUpdate();
......
......@@ -60,6 +60,12 @@
<file>qml/components/AskWhenRemovePopup.qml</file>
<file>qml/FFTGraphView.qml</file>
<file>qml/BarMapView.qml</file>
<file>qml/InformationScreen/InformationWindow.qml</file>
<file>qml/InfoScreenPropertiesView.qml</file>
<file>qml/InformationScreen/SpotifyTrack.qml</file>
<file>qml/InformationScreen/AngebotsModel.qml</file>
<file>qml/InformationScreen/AngebotsManagmentComponent.qml</file>
<file>qml/InformationScreen/Lauftext.qml</file>
<file>icons/sort_order/sort-by-alphabet.svg</file>
<file>icons/sort_order/sort-by-alphabet_16px.png</file>
<file>icons/sort_order/sort-by-alphabet_24px.png</file>
......
import QtQuick 2.12
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.12
import QtQuick.Dialogs 1.2
import QtQuick.Window 2.12
import custom.licht 1.0
import "InformationScreen"
Item{
property var window: InformationWindow{}
property AngebotsModel angebote: AngebotsModel{}
GridLayout{
columns: 2
anchors.fill: parent
anchors.leftMargin: 5
Label{
text: "Modality:"
}
RowLayout{
Layout.fillWidth: true
RadioButton{
text: "Hide"
onCheckedChanged: if(checked) window.visibility = Window.Hidden;
checked: window.visibility === Window.Hidden || window.visibility === Window.Minimized
}
RadioButton{
text: "Windowed"
onCheckedChanged: if(checked) window.visibility = Window.Windowed;
checked: window.visibility === Window.Maximized || window.visibility === Window.Windowed
}
RadioButton{
text: "Full Screen"
onCheckedChanged: if(checked) window.visibility = Window.FullScreen;
checked: window.visibility === Window.FullScreen
}
}
Label{
text: "Background color:"
}
Button{
id:colorButton
text: "Select Color"
Component.onCompleted: {
colorButton.background.color = window.color;
colorDialog.color = window.color;
}
ColorDialog{
id: colorDialog
onRejected: {
colorButton.background.color = color;
window.color = color;
}
onCurrentColorChanged: {
colorButton.background.color = currentColor;
window.color = currentColor;
}
}
onClicked: colorDialog.open();
}
AngebotsManagmentComponent{
Layout.columnSpan: 2
model: angebote
Layout.fillHeight: true
Layout.fillWidth: true
}
}
}
import QtQuick 2.12
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.12
import "../"
import "../components"
Item {
property alias model : angebote.model;
ColumnLayout{
id: columnLayout
anchors.top: parent.top
anchors.left: parent.left
anchors.bottom: parent.bottom
width: 200
ListView{
property var currentData: currentItem ? model.get(currentIndex) : null
property bool isCurrentlySection: currentData ? currentData.section === model.null_section : false
property bool isCurrentlyEntry: currentData ? currentData.section !== model.null_section : false
Layout.leftMargin: -5
id: angebote
delegate: ItemDelegate{
id: delegate
onClicked: angebote.currentIndex = index;
text: section === angebote.model.null_section ? name : " " + name
font.pixelSize: section === angebote.model.null_section ? 16 : 13
width: angebote.width
Component.onCompleted: {
for(var i in contentItem)
console.log(i,contentItem[i])
contentItem.leftPadding = -11
contentItem.color = Qt.binding(function(){
if(offered){
if(section !== angebote.model.null_section){
console.log( "parent section",section.name," is offered : " , section.offered)
return section.offered ? "black" : "grey";
}else{
return "black"
}
}else{
return "grey"
}
})
}
Binding{
target: delegate.contentItem
property: "color"
value: delegate.isoffered ? "black" : "grey"
}
}
highlight: Rectangle{
color: "lightblue"
}
clip: true
Layout.fillHeight: true
Layout.fillWidth: true
}
Button{
id: deleteButton
text: "remove"
onClicked: angebote.model.removeEntry(angebote.currentIndex);
Layout.fillWidth: true
Layout.margins: 5
enabled: angebote.currentIndex >= 0 && (angebote.isCurrentlyEntry || angebote.isCurrentlySection&&(angebote.model.count - 1 === angebote.currentIndex || angebote.model.get(angebote.currentIndex+1).section === angebote.model.null_section))
}
}
GridLayout{
anchors.left: columnLayout.right
anchors.top: parent.top
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.leftMargin: 5
columns: 2
rowSpacing: 10
columnSpacing: 10
Label{
text: "Name"
}
TextInputField{
Layout.fillWidth: true
text: angebote.currentData ? angebote.currentData.name : "No Entry selected";
enabled: angebote.currentItem
onTextChanged: {
if(angebote.currentData){
angebote.currentData.name = text;
}
}
}
Label{
text: "Description"
}
TextInputField{
Layout.fillWidth: true
text: angebote.isCurrentlyEntry ? angebote.currentData.description : angebote.isCurrentlySection ? "No description possible":"No Entry selected";
enabled: angebote.isCurrentlyEntry
onTextChanged: if(angebote.isCurrentlyEntry)angebote.currentData.description = text
}
Label{
text: "Price"
}
TextInputField{
Layout.fillWidth: true
text: angebote.isCurrentlyEntry ? angebote.currentData.price : "Can not have a price"
enabled: angebote.isCurrentlyEntry
onTextChanged: if(angebote.currentItem)angebote.currentData.price = text
}
Label{
text: "Offered"
}
CheckBox{
enabled: angebote.currentItem
checked: angebote.currentData ? angebote.currentData.offered : false
onCheckedChanged: if(angebote.currentData)angebote.model.setProperty(angebote.currentIndex,"offered",checked)
Layout.margins: -10
Text {
visible: angebote.currentData ? angebote.currentData.section !== angebote.model.null_section && !angebote.currentData.section.offered : false
anchors.left: parent.right
anchors.baseline: parent.baseline
text: "The section is not offered, so this Entry will be not offered too"
}
}
Item{
id: filler
Layout.fillHeight: true
Layout.columnSpan: 2
}
RowLayout{
Layout.fillWidth: true
Layout.columnSpan: 2
Button{
text: "Add Section"
Layout.margins: 5
Layout.fillWidth: true
onClicked: angebote.model.addSection("New section",true)
}
Button{
text: "Add Angebot"
Layout.margins: 5
Layout.fillWidth: true
enabled: angebote.model.count > 0
onClicked: angebote.model.addEntryAtIndex(angebote.currentIndex)
}
}
}
}
import QtQuick 2.12
import QtQml.Models 2.12
ListModel{
property QtObject null_section: QtObject{}
property ListModel sections: ListModel{
}
function addSection(name, offered){
append({"name":name, "offered": offered, "section" : null_section});
sections.append(get(count-1));
}
function changeSection(index, newSection){
if(index<0||index>=count)
return;
if(get(index).section === null_section)
return;
if(get(index).section === newSection)
return;
for(var i = 0; i<count;++i){
if(get(i) === newSection){
move(index,i+1)
break;
}
}
}
function removeEntry(index){
if(index>=0&&index<count){
if(get(index).section === null_section){
if(index === count-1 || get(index+1).section === null_section){
for(var i = 0; i < sections.count ; ++i){
if(sections.get(i) === get(index)){
sections.remove(i);
break;
}
}
remove(index);
}
}else{
remove(index);
}
}
}
function addEntryAtIndex(index){
//find section
var section = null;
for(var i = index;i>=0;--i){
if(get(i).section === null_section){
section = get(i);
break;
}
}
if(section){
insert(index+1, {"name": "Neues Getränk", "description":"","zutaten":"","price":"","section":section,"offered":true})
}
}
function addEntry(name, description, zutaten, price, section, offered){
if(section === null || section === undefined){
throw "Illegal arguments";
}
//find index to insert:
var insertIndex = -1;
for(var i = 0; i < count; ++i){
if(get(i) === section){
for(; i < count; ++i){
if(get(i).section === null_section){
insertIndex = i-1;
break;
}
}
if(insertIndex === -1){
insertIndex = count-1;
}
break;
}
}
if(insertIndex === -1){
throw "Parent section does not exists!";
}
insert(insertIndex,{"name": name, "description":description,"zutaten":zutaten,"price":price,"section":section,"offered":offered});
}
function moveOnePosition(index,up){
if(index>0 && index < count){
if(get(index).section !== null_section){
var dir = up ? 1 : -1;
if(up&&index<=1 || !up&&index>=count-1)
return;
if(get(index+dir).section === get(index).section){
move(index,index+dir,1);
}
}else{
var to = index + dir;
while(to >= 0 && to < count && !get(to).section){
to += dir;
}
if(to === index + dir)
return;
var objectsToMove = 1;
var i = index + 1;
while(i<count && !get(i).section){
++i;
++objectsToMove;
}
move(index,to,objectsToMove)
}
}
}
function moveOnePositionUp(index){
moveOnePosition(index, true);
}
function moveOnePositionDown(index){
moveOnePosition(index, true);
}
}
import QtQuick 2.12
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.12
import QtQuick.Window 2.12
ApplicationWindow {
id:window
flags: Qt.Window | Qt.WindowFullscreenButtonHint
onVisibilityChanged: console.log("visibility is now",visibility)
onVisibleChanged: console.log("visible",visible)
header: Rectangle{
color: "red"
height: 30
visible: true
}
SpotifyTrack{
id: currentSpotifyTrack
visible: true//spotify.currentUser !== null
coverImageSource: spotify.currentTrack ? spotify.currentTrack.album.images.data(spotify.currentTrack.album.images.index(0,0)).url : ""
text: spotify.currentTrack ? spotify.currentTrack.name + " ("+spotify.currentTrack.artists.data(spotify.currentTrack.artists.index(0,0)).name+")<br><font size=\"12\"> "+spotify.currentTrack.album.albumType + ": " + spotify.currentTrack.album.name + "("+spotify.currentTrack.album.releaseDate+")"+" </font>": "No Track is playing"
height: 50
width: parent.width
Timer{
interval: 1000
repeat: true
running: true
onTriggered: {
if(spotify.currentPlayingStatus && spotify.currentTrack){
currentSpotifyTrack.progress = spotify.currentPlayingStatus.progressMs/spotify.currentTrack.durationMs;
}
}
}
}
/*Lauftext{
text: "TEST hihihi"
speed: 1
width: window.width
height: 30
y: 60
}*/
/*footer: SpotifyTrack{
id: currentSpotifyTrack
visible: spotify.currentUser !== null
coverImageSource: spotify.currentTrack ? spotify.currentTrack.album.images[0] : ""
text: spotify.currentTrack ? spotify.currentTrack.name + " ("+spotify.currentTrack.artists[0]+")<br><font size=\"12\"> "+spotify.currentTrack.album.albumType + ": " + spotify.currentTrack.album.name + "("+spotify.currentTrack.album.releaseDate+")"+" </font>": ""
height: 50
Timer{
interval: 1000
repeat: true
running: true
onTriggered: {
if(spotify.currentPlayingStatus && spotify.currentTrack){
currentSpotifyTrack.progress = spotify.currentPlayingStatus.progressMs/spotify.currentTrack.durationMs;
}
}
}
}*/
}
import QtQuick 2.12
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.12
import "../../"
Label {
id: label
property double speed: 100
NumberAnimation{
target: label
property: "leftPadding"
duration: (label.width + label.contentWidth)/100 * (1/speed) * 1000
from: label.width + label.contentWidth
onFromChanged: restart()
to: -label.contentWidth
running: true
loops: Animation.Infinite
}
}
import QtQuick 2.12
import QtQuick.Controls 2.5
import QtQuick.Layouts 1.12
import QtQuick.Dialogs 1.2
import QtQuick.Window 2.12
Rectangle {
id:root
color: "#1db954" //spotify green
property alias coverImageSource: image.source
property var progress: null
property alias text: label.text
Image {
id: image
fillMode: Image.PreserveAspectFit
anchors.margins: 5
anchors.left: parent.left
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.right: label.left
}
Label{
id: label
anchors.top: parent.top
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.margins: 5
}
Rectangle{
visible: root.progress !== null
height: 3
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
color: "grey"
Rectangle{
anchors.left: parent.left
anchors.top: parent.top
anchors.bottom: parent.bottom
width: parent.width * root.progress
color: "white"
Behavior on width {
NumberAnimation { easing.type: Easing.Linear; duration: 1000 }
}
}
}
}
import QtQuick 2.7
import QtQuick 2.12
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.0
import custom.licht 1.0
......@@ -66,6 +66,9 @@ ApplicationWindow {
VerticalTabButton {
text: qsTr("Map View")
}
VerticalTabButton {
text: qsTr("Info Screen")
}
VerticalTabButton {
text: qsTr("Login")
}
......@@ -124,6 +127,8 @@ ApplicationWindow {
id: mapView
}
InfoScreenPropertiesView{}
LoginView{}
SettingsView{}
......
......@@ -3,7 +3,7 @@
namespace Spotify::Objects{
AlbumObject_simplified::AlbumObject_simplified(const QJsonObject& object): album_group(getOptional<QString>(object,"album_group")), album_type(object["album_type"].toString()),artists(object["artists"].toArray()),id(object["id"].toString()),images(object["images"].toArray()),name(object["name"].toString())
AlbumObject_simplified::AlbumObject_simplified(const QJsonObject& object): album_group(getOptional<QString>(object,"album_group")), album_type(object["album_type"].toString()),artists(object["artists"].toArray()),id(object["id"].toString()),images(object["images"].toArray()),name(object["name"].toString()),release_date(object["release_date"].toString())
{
}
......
......@@ -16,9 +16,14 @@ namespace Spotify::Objects{
/**
* @brief The AlbumObject_simplified class https://developer.spotify.com/documentation/web-api/reference/object-model/#album-object-simplified
*/
class AlbumObject_simplified
class AlbumObject_simplified : public QObject
{
Q_GADGET
Q_OBJECT
Q_PROPERTY(QString name MEMBER name CONSTANT)
Q_PROPERTY(QString albumType MEMBER album_type CONSTANT)
Q_PROPERTY(QString releaseDate MEMBER release_date CONSTANT)
Q_PROPERTY(QAbstractListModel * images READ getImages CONSTANT)
Q_PROPERTY(QAbstractListModel * artists READ getArtists CONSTANT)
public:
/**
* @brief album_group The field is present when getting an artist’s albums. Possible values are “album”, “single”, “compilation”, “appears_on”. Compare to album_type this field represents relationship between the artist and the album.
......@@ -31,7 +36,7 @@ public:
/**
* @brief artists The artists of the album. Each artist object includes a link in href to more detailed information about the artist.
*/
const ArtistVector artists;
ArtistVector artists;
/**
* @brief id The [/documentation/web-api/#spotify-uris-and-ids) for the album.
*/
......@@ -39,14 +44,19 @@ public:
/**
* @brief images The cover art for the album in various sizes, widest first.
*/
const ImageVector images;
ImageVector images;
/**
* @brief name The name of the album. In case of an album takedown, the value may be an empty string.
*/
const QString name;
/**
* @brief release_date TODO
*/
const QString release_date;
public:
AlbumObject_simplified(const QJsonObject& object);
QAbstractListModel * getImages(){return &images;}
QAbstractListModel * getArtists(){return &artists;}
};
}
......
......@@ -14,6 +14,8 @@ namespace Spotify::Objects{
class ArtistObject_simplified
{
Q_GADGET
Q_PROPERTY(QString name MEMBER name CONSTANT)
Q_PROPERTY(QString id MEMBER id CONSTANT)
public:
/**
* @brief href A link to the Web API endpoint providing full details of the artist.
......@@ -38,13 +40,6 @@ class ArtistVector : public ModelVector<ArtistObject_simplified>{
public:
ArtistVector() = default;
ArtistVector(const QJsonArray & array);
virtual QVariant data(const QModelIndex &index, int role) const override{
Q_UNUSED(role);
if(index.row()>=0&&index.row()<int(getVector().size())){
return QVariant::fromValue(&(getVector()[index.row()]));
}
return QVariant();
}
};
}
......
......@@ -6,7 +6,7 @@
namespace Spotify::Objects{
CurrentPlayingObject::CurrentPlayingObject(const QJsonObject &object, const long receivedTimestamp) : timestamp(static_cast<long>(object["timestamp"].toDouble())),receivedTimestamp(receivedTimestamp),progress_ms(getOptional<int>(object, "progress_ms")), is_playing(object["is_playing"].toBool()), item(getOptional<TrackObject_full>(object,"item")), currently_playing_type(object["currently_playing_type"].toString())
CurrentPlayingObject::CurrentPlayingObject(const QJsonObject &object, std::optional<TrackObject_full> & item, const long receivedTimestamp) : timestamp(static_cast<long>(object["timestamp"].toDouble())),receivedTimestamp(receivedTimestamp),progress_ms(getOptional<int>(object, "progress_ms")), is_playing(object["is_playing"].toBool()), item(item), currently_playing_type(object["currently_playing_type"].toString())
{
}
......@@ -25,4 +25,18 @@ int CurrentPlayingObject::getProgressInMs()const{
return -1;
}
QVariant CurrentPlayingObject::getProgressAsVariant() const{
if(int res = getProgressInMs();res>=0){
return res;
}
return {};
}
Objects::TrackObject_full * CurrentPlayingObject::getCurrentTrackAsPointer() {
if(item){
return &*item;
}
return nullptr;
}
}
......@@ -9,9 +9,13 @@
namespace Spotify::Objects{
//https://developer.spotify.com/documentation/web-api/reference/player/get-the-users-currently-playing-track/
class CurrentPlayingObject
class CurrentPlayingObject: public QObject
{
//Q_GADGET
Q_OBJECT
Q_PROPERTY(QVariant progressMs READ getProgressAsVariant CONSTANT)
Q_PROPERTY(QString currentlyPlayingType MEMBER currently_playing_type CONSTANT)
Q_PROPERTY(bool isPlaying MEMBER is_playing CONSTANT)
Q_PROPERTY(Objects::TrackObject_full * currentTrack READ getCurrentTrackAsPointer CONSTANT)
public:
/**
* @brief timestamp Unix Millisecond Timestamp when data was updated at the spotify server
......@@ -32,19 +36,24 @@ public:
/**
* @brief item The currently playing track. Can be null.
*/
const std::optional<TrackObject_full> item;