aboutsummaryrefslogtreecommitdiff
path: root/src-qt5/desktop-utils
diff options
context:
space:
mode:
Diffstat (limited to 'src-qt5/desktop-utils')
-rw-r--r--src-qt5/desktop-utils/lumina-mediaplayer/PianoBarProcess.cpp230
-rw-r--r--src-qt5/desktop-utils/lumina-mediaplayer/PianoBarProcess.h73
-rw-r--r--src-qt5/desktop-utils/lumina-mediaplayer/extra/Pandora.svg151
-rw-r--r--src-qt5/desktop-utils/lumina-mediaplayer/extra/resources.qrc5
-rw-r--r--src-qt5/desktop-utils/lumina-mediaplayer/lumina-mediaplayer.pro142
-rw-r--r--src-qt5/desktop-utils/lumina-mediaplayer/main.cpp30
-rw-r--r--src-qt5/desktop-utils/lumina-mediaplayer/mainUI.cpp341
-rw-r--r--src-qt5/desktop-utils/lumina-mediaplayer/mainUI.h77
-rw-r--r--src-qt5/desktop-utils/lumina-mediaplayer/mainUI.ui477
9 files changed, 1368 insertions, 158 deletions
diff --git a/src-qt5/desktop-utils/lumina-mediaplayer/PianoBarProcess.cpp b/src-qt5/desktop-utils/lumina-mediaplayer/PianoBarProcess.cpp
index 667ebefb..88abce82 100644
--- a/src-qt5/desktop-utils/lumina-mediaplayer/PianoBarProcess.cpp
+++ b/src-qt5/desktop-utils/lumina-mediaplayer/PianoBarProcess.cpp
@@ -10,64 +10,132 @@
#include <QDir>
#include <QFile>
#include <QTextStream>
-
+#include <QApplication>
#include <LUtils.h>
PianoBarProcess::PianoBarProcess(QWidget *parent) : QObject(parent){
setupProcess();
-
+ saveTimer = new QTimer(this);
+ saveTimer->setInterval(100); //1/10 second (just enough to change a few settings at once before dumping to disk)
+ saveTimer->setSingleShot(true);
+ connect(saveTimer, SIGNAL(timeout()), this, SLOT(saveSettingsFile()) );
+ if( !loadSettings() ){ GenerateSettings(); }
}
PianoBarProcess::~PianoBarProcess(){
+ if(PROC->state()!=QProcess::NotRunning){
+ PROC->kill();
+ }
+}
+PianoBarProcess::State PianoBarProcess::currentState(){
+ return cState;
}
// ===== PUBLIC ======
//Interaction functions
-bool PianoBarProcess::isSetup(); //email/password already saved for use or not
-void PianoBarProcess::setLogin(QString email, QString pass);
-void PianoBarProcess::closePianoBar(); //"q"
+bool PianoBarProcess::isSetup(){ //email/password already saved for use or not
+ return !(settingValue("user").isEmpty() || settingValue("password").isEmpty());
+}
+
+void PianoBarProcess::setLogin(QString email, QString pass){
+ setSettingValue("user",email);
+ setSettingValue("password",pass);
+}
+
+QString PianoBarProcess::email(){
+ return settingValue("user");
+}
+
+QString PianoBarProcess::password(){
+ return settingValue("password");
+}
+
+void PianoBarProcess::closePianoBar(){ //"q"
+ sendToProcess("q");
+}
-QString PianoBarProcess::currentStation(); //Re-direct for the "autostartStation()" function;
-QStringList PianoBarProcess::stations();
-void PianoBarProcess::setCurrentStation(QString station);
+QString PianoBarProcess::currentStation(){ return cstation.simplified(); }
+QStringList PianoBarProcess::stations(){ return stationList; }
+void PianoBarProcess::setCurrentStation(QString station){
+ cstation = station;
+ sendToProcess("s");
+}
-void PianoBarProcess::deleteCurrentStation(); //"d"
-void PianoBarProcess::createNewStation(); //"c"
-void PianoBarProcess::createStationFromCurrentSong(); //"v"
-void PianoBarProcess::changeStation(); //"s"
+void PianoBarProcess::deleteCurrentStation(){ //"d" -> "y"
+ if(cstation == "QuickMix" || cstation=="Thumbprint Radio"){ return; } //cannot delete these stations - provided by Pandora itself
+ sendToProcess("d"); //delete current station
+ sendToProcess("y",true); //yes, we want to delete it
+ //Now need to automatically change to another station
+ setCurrentStation("QuickMix"); //this is always a valid station
+}
+
+//void PianoBarProcess::createNewStation(); //"c"
+void PianoBarProcess::createStationFromCurrentSong(){ //"v" -> "s"
+ sendToProcess("v");
+ sendToProcess("s",true);
+ setCurrentStation("<NEW>"); //internal definition for auto-switching to a new station
+}
+
+void PianoBarProcess::createStationFromCurrentArtist(){ //"v" -> "a"
+ sendToProcess("v");
+ sendToProcess("a",true);
+ setCurrentStation("<NEW>"); //internal definition for auto-switching to a new station
+}
//Settings Manipulation
QString PianoBarProcess::audioQuality(){ // "audio_quality" = [low, medium, high]
-
+ return settingValue("audio_quality");
}
-void PianoBarProcess::setAudioQuality(QString); // [low, medium, high]
-QString PianoBarProcess::autostartStation(); //"autostart_station" = ID
-void PianoBarProcess::setAutostartStation(QString);
-QString PianoBarProcess::proxy(); //"proxy" = URL (example: "http://USER:PASSWORD@HOST:PORT/" )
-void PianoBarProcess::setProxy(QString);
-QString PianoBarProcess::controlProxy(); //"control_proxy" = URL (example: "http://USER:PASSWORD@HOST:PORT/" )
-void PianoBarProcess::setControlProxy(QString);
+void PianoBarProcess::setAudioQuality(QString val){ // [low, medium, high]
+ setSettingValue("audio_quality",val);
+}
-// ====== PUBLIC SLOTS ======
-void PianoBarProcess::play(); // "P"
-void PianoBarProcess::pause(); //"S"
+QString PianoBarProcess::autostartStation(){ //"autostart_station" = ID
+ return settingValue("autostart_station");
+}
+
+void PianoBarProcess::setAutostartStation(QString id){
+ setSettingValue("autostart_station", id);
+}
-void PianoBarProcess::volumeDown(); //"("
-void PianoBarProcess::volumeUp(); //")"
+QString PianoBarProcess::proxy(){ //"proxy" = URL (example: "http://USER:PASSWORD@HOST:PORT/" )
+ return settingValue("proxy");
+}
+
+void PianoBarProcess::setProxy(QString url){
+ setSettingValue("proxy",url);
+}
+
+QString PianoBarProcess::controlProxy(){ //"control_proxy" = URL (example: "http://USER:PASSWORD@HOST:PORT/" )
+ return settingValue("control_proxy");
+}
+
+void PianoBarProcess::setControlProxy(QString url){
+ setSettingValue("control_proxy", url);
+}
-void PianoBarProcess::skipSong(); //"n"
-void PianoBarProcess::loveSong(); // "+"
-void PianoBarProcess::tiredSong(); // "t"
-void PianoBarProcess::banSong(); //"-"
-void PianoBarProcess::bookmarkSong(); //"b"
+// ====== PUBLIC SLOTS ======
+void PianoBarProcess::play(){
+ if(PROC->state() == QProcess::NotRunning){
+ PROC->start();
+ }else{
+ sendToProcess("P");
+ cState = PianoBarProcess::Running;
+ emit currentStateChanged(cState);
+ }
+}
-void PianoBarProcess::explainSong(); //"e"
+void PianoBarProcess::pause(){
+ sendToProcess("S");
+ cState = PianoBarProcess::Paused;
+ emit currentStateChanged(cState);
+}
-void PianoBarProcess::requestHistory(); // "h"
-void PianoBarProcess::requestSongInfo(); //"i"
-void PianoBarProcess::requestUpcoming(); //"u"
+void PianoBarProcess::skipSong(){
+ sendToProcess("n");
+}
// ====== PRIVATE ======
void PianoBarProcess::GenerateSettings(){
@@ -76,17 +144,20 @@ void PianoBarProcess::GenerateSettings(){
currentSettings << "format_list_song = %r::::%t::::%a"; //[rating, title, artist]
currentSettings << "format_nowplaying_song = %r::::%t::::%a::::%l::::%u::::%s"; // [rating, title, artist, album, details url, station (if not quickmix)]
currentSettings << "format_nowplaying_station = %n::::%i"; //[name, id]
+ saveSettingsFile(); //save this to disk *now* - needed before starting the pianobar process
}
-void PianoBarProcess::loadSettings(){
+bool PianoBarProcess::loadSettings(){
currentSettings.clear();
- QFile file(settingspath);
- if(!file.exists()){ return; }
+ QFile file(settingsPath);
+ if(!file.exists()){ return false; }
if(file.open(QIODevice::ReadOnly)){
QTextStream in(&file);
currentSettings = in.readAll().split("\n");
file.close();
+ return true;
}
+ return false;
}
QString PianoBarProcess::settingValue(QString var){
@@ -102,14 +173,15 @@ void PianoBarProcess::setSettingValue(QString var,QString val){
if(currentSettings[i].startsWith(var+" = ")){ currentSettings[i] = var+" = "+val; changed = true; }
}
if(!changed){ currentSettings << var+" = "+val; }
+ saveTimer->start(); //save this to disk in a moment
}
void PianoBarProcess::saveSettingsFile(){
//Ensure the parent directory exists first
- QDir dir(settingspath.section("/",0,-2));
+ QDir dir(settingsPath.section("/",0,-2));
if(!dir.exists()){ dir.mkpath(dir.absolutePath()); }
//Now save the settings
- QFile file(settingspath);
+ QFile file(settingsPath);
if(file.open(QIODevice::WriteOnly | QIODevice::Truncate)){
QTextStream out(&file);
out << currentSettings.join("\n");
@@ -125,7 +197,7 @@ void PianoBarProcess::setupProcess(){
else{ configdir.append("/lumina-desktop"); }
QProcessEnvironment penv;
penv.insert("XDG_CONFIG_HOME",configdir);
- settingspath = configdir+"/pianobar/config";
+ settingsPath = configdir+"/pianobar/config";
PROC->setProcessEnvironment(penv);
//Now setup the rest of the process
PROC->setProcessChannelMode(QProcess::MergedChannels);
@@ -133,35 +205,87 @@ void PianoBarProcess::setupProcess(){
LUtils::isValidBinary(bin); //will change "bin" to the full path
PROC->setProgram(bin);
connect(PROC, SIGNAL(readyRead()), this, SLOT(ProcUpdate()) );
+ connect(PROC, SIGNAL(stateChanged(QProcess::ProcessState)), this, SLOT(ProcStateChanged(QProcess::ProcessState)) );
+ cState = PianoBarProcess::Stopped;
+}
+
+void PianoBarProcess::sendToProcess(QString txt, bool withreturn){
+ if(PROC->state()==QProcess::Running){
+ if(withreturn){ PROC->write( QString(txt+"\r\n").toLocal8Bit() ); }
+ else{ PROC->write( QString(txt).toLocal8Bit() ); }
+ }
}
// ====== PRIVATE SLOTS ======
void PianoBarProcess::ProcUpdate(){
- QStringList info = QString(PROC->readAllStandardOutput()).split("\n");
+ QString tmp = QString(PROC->readAllStandardOutput()).replace("\r","\n").remove("\u001B[2K");
+ QStringList info = tmp.split("\n",QString::SkipEmptyParts);
+
//NOTE: Need to have a cache of info lines which can carry over between updates as needed (for questions, etc)
- qDebug() << "Got Update:" << info;
+ //qDebug() << "Got Update:" << info;
for(int i=0; i<info.length(); i++){
+ //First handle any pending cache of listing lines
+ if((info[i].startsWith("\t")||info[i].startsWith(" ")) && info[i].contains(")")){
+ if(info[i].simplified().startsWith("0) ")){ infoList.clear(); }
+ infoList << info[i].section(") ",1,-1).simplified();
+ continue; //done handling this line
+ }else if(!info[i].startsWith("[?]") && !infoList.isEmpty()){
+ emit NewList(infoList);
+ infoList.clear();
+ }
+ //Now parse the lines for messages/etc
if(info[i].startsWith("|>")){
//Now playing line (station, or song)
QStringList data = info[i].section(">",1,-1).simplified().split("::::"); //Make sure to chop the line prefix off first
if(data.length()==2){ //station
- cstation = data[0]; //save the name for later
+ cstation = data[0].simplified(); //save the name for later
emit NowPlayingStation(data[0], data[1]);
+ if(stationList.isEmpty()){
+ //Need to prompt to list all the available stations
+ sendToProcess("s",true);//line return cancels the prompt
+ //sendToProcess("",true); //empty line - cancels the prompt
+ }
//Automatically save this station for autostart next time (make toggle-able later)
if(data[1]!=autostartStation()){ setAutostartStation(data[1]); }
}else if(data.length()==6){ //song
emit NowPlayingSong( data[0]=="<3", data[1], data[2], data[3], data[4], data[5] );
}
+ //If a new song/station is detected, ensure that the state is set to "Running"
+ if(cState!=PianoBarProcess::Running){
+ cState = PianoBarProcess::Running;
+ emit currentStateChanged(cState);
+ }
}else if(info[i].startsWith("(i) ")){ //informational line
emit NewInformation(info[i].section(" ",1,-1));
}else if(info[i].startsWith("[?] ")){ //waiting for reply to question
- if(info[i].contains("Select Station:"){
- //Find the number before this line which corresponds to the cstation variable/name
- for(j=i-1; j>=0; j--){
- if(info[j].contains(")" && info[j].contains(cstation) ){
- PROC->write(info[j].section(")",0,0).simplified() + "\r\n");
+ //qDebug() << "Got Question:" << info[i] << infoList;
+ if(info[i].contains("Select station:")){
+ //qDebug() << "Change to Station:" << cstation;
+ //Clean up the station list a bit first (remove the quickmix-status)
+ for(int j=0; j<infoList.length(); j++){
+ infoList[j] = infoList[j].simplified();
+ if(infoList[j].startsWith("q ")){ infoList[j] = infoList[j].section("q ",1,-1); }
+ if(infoList[j].startsWith("Q ")){ infoList[j] = infoList[j].section("Q ",1,-1); }
+ }
+ if(cstation=="<NEW>"){
+ //Compare the new list to the previous list and switch to the new one automatically
+ for(int j=0; j<infoList.length(); j++){
+ if(!stationList.contains(infoList[j])){ cstation = infoList[j]; break; }
+ }
+ }
+ stationList = infoList; //save this list for later
+ infoList.clear();
+ emit StationListChanged(stationList);
+ //Find the station number which corresponds to the cstation variable/name
+ for(int j=0; j<stationList.length(); j++){
+ if(stationList[j].endsWith(cstation) ){
+ //qDebug() << "Activate Station:" << stationList[i];
+ sendToProcess(QString::number(j), true);
break;
+ }else if(j==stationList.length()-1){
+ //qDebug() << "Activate Last Station:" << stationList[i];
+ sendToProcess(QString::number(stationList.length()-1), true);
}
}
}
@@ -169,10 +293,16 @@ void PianoBarProcess::ProcUpdate(){
}else if(info[i].startsWith("#")){
//Time Stamp
QTime stamp = QTime::fromString(info[i].section("/",0,0).section("-",1,-1), "mm:ss");
- int curS = 60*stamp.minutes() + stamp.seconds(); //time remaining
+ int curS = 60*stamp.minute() + stamp.second(); //time remaining
stamp = QTime::fromString(info[i].section("/",1,-1), "mm:ss");
- int totS = 60*stamp.minutes() + stamp.sections(); //time total
+ int totS = 60*stamp.minute() + stamp.second(); //time total
emit TimeUpdate(totS-curS, totS);
}
}
}
+
+void PianoBarProcess::ProcStateChanged(QProcess::ProcessState stat){
+ if(stat == QProcess::NotRunning){ cState = PianoBarProcess::Stopped; }
+ else{ cState = PianoBarProcess::Paused; }
+ emit currentStateChanged(cState);
+}
diff --git a/src-qt5/desktop-utils/lumina-mediaplayer/PianoBarProcess.h b/src-qt5/desktop-utils/lumina-mediaplayer/PianoBarProcess.h
index 83404e0c..f250c964 100644
--- a/src-qt5/desktop-utils/lumina-mediaplayer/PianoBarProcess.h
+++ b/src-qt5/desktop-utils/lumina-mediaplayer/PianoBarProcess.h
@@ -13,7 +13,7 @@
#include <QObject>
#include <QWidget>
#include <QProcess>
-
+#include <QTimer>
// #define PIANOBAR_FIFO QString(getenv("XDG_CONFIG_HOME"))+"/lumina-desktop/pianobar/ctl"
// #define PIANOBAR_CONFIG QString(getenv("XDG_CONFIG_HOME"))+"/lumina-desktop/pianobar/config"
@@ -31,16 +31,14 @@ public:
//Interaction functions
bool isSetup(); //email/password already saved for use or not
void setLogin(QString email, QString pass);
+ QString email();
+ QString password();
+
void closePianoBar(); //"q"
QString currentStation(); //Re-direct for the "autostartStation()" function;
QStringList stations();
void setCurrentStation(QString station);
-
- void deleteCurrentStation(); //"d"
- void createNewStation(); //"c"
- void createStationFromCurrentSong(); //"v"
- void changeStation(); //"s"
//Settings Manipulation
QString audioQuality(); // "audio_quality" = [low, medium, high]
@@ -52,52 +50,65 @@ public:
QString controlProxy(); //"control_proxy" = URL (example: "http://USER:PASSWORD@HOST:PORT/" )
void setControlProxy(QString);
-public slots:
- void play(); // "P"
- void pause(); //"S"
-
- void volumeDown(); //"("
- void volumeUp(); //")"
-
- void skipSong(); //"n"
- void loveSong(); // "+"
- void tiredSong(); // "t"
- void banSong(); //"-"
- void bookmarkSong(); //"b"
-
- void explainSong(); //"e"
-
- void requestHistory(); // "h"
- void requestSongInfo(); //"i"
- void requestUpcoming(); //"u"
-
-
private:
//Process
- QProcess PROC;
+ QProcess *PROC;
+ PianoBarProcess::State cState;
+ QStringList infoList;
void setupProcess();
+ void sendToProcess(QString, bool withreturn = false);
//Settings file management
QStringList currentSettings; //cache of the settings file (file is really small);
QString settingsPath; //location of the settings file
+ QTimer *saveTimer;
void GenerateSettings();
- void loadSettings();
+ bool loadSettings();
QString settingValue(QString);
void setSettingValue(QString,QString);
- void saveSettingsFile();
+
//Cached Info
QString cstation; //current station
- QStringList stationNames;
+ QStringList stationList;
+
+public slots:
+ void play(); // "P"
+ void pause(); //"S"
+
+ void volumeDown(){ sendToProcess("("); } //"("
+ void volumeUp(){ sendToProcess(")"); } //")"
+
+ void skipSong(); //"n"
+ void loveSong(){ sendToProcess("+"); } // "+"
+ void tiredSong(){ sendToProcess("t"); } // "t"
+ void banSong(){ sendToProcess("-"); } //"-"
+ void bookmarkSong(){ sendToProcess("b"); sendToProcess("s", true); } //"b"->"s"
+ void bookmarkArtist(){ sendToProcess("b"); sendToProcess("a",true); } //"b"->"a"
+
+ void deleteCurrentStation(); //"d"
+ //void createNewStation(); //"c"
+ void createStationFromCurrentSong(); //"v" -> "s"
+ void createStationFromCurrentArtist(); //"v" -> "a"
+
+ void explainSong(){ sendToProcess("e"); } //"e"
+
+ void requestHistory(){ sendToProcess("h"); } // "h" NOTE: Long series of interactive prompts - better to avoid for now
+ void requestSongInfo(){ sendToProcess("i"); } //"i" NOTE: This will re-print the current station/song information
+ void requestUpcoming(){ sendToProcess("u"); } //"u" NOTE: This will often return "(i) No songs in queue" - best to run this after a "Receiving new playlist" info message
private slots:
void ProcUpdate();
-
+ void ProcStateChanged(QProcess::ProcessState);
+ void saveSettingsFile();
signals:
void NewInformation(QString); //random status updates/information
void NowPlayingStation(QString, QString); //[name, id]
void NowPlayingSong(bool, QString,QString,QString, QString, QString); //[isLoved, title, artist, album, detailsURL, fromStation]
void TimeUpdate(int, int); //[current secs, total secs];
+ void NewList(QStringList); //arranged in order: 0-end
+ void StationListChanged(QStringList);
+ void currentStateChanged(PianoBarProcess::State);
};
#endif
diff --git a/src-qt5/desktop-utils/lumina-mediaplayer/extra/Pandora.svg b/src-qt5/desktop-utils/lumina-mediaplayer/extra/Pandora.svg
new file mode 100644
index 00000000..62f656c1
--- /dev/null
+++ b/src-qt5/desktop-utils/lumina-mediaplayer/extra/Pandora.svg
@@ -0,0 +1,151 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="256"
+ height="256"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.47 r22583"
+ sodipodi:docname="pandora.svg"
+ version="1.0"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape">
+ <defs
+ id="defs4">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 128 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="256 : 128 : 1"
+ inkscape:persp3d-origin="128 : 85.333333 : 1"
+ id="perspective2850" />
+ <linearGradient
+ inkscape:collect="always"
+ id="linearGradient2555">
+ <stop
+ style="stop-color: rgb(255, 255, 255); stop-opacity: 1;"
+ offset="0"
+ id="stop2557" />
+ <stop
+ style="stop-color: rgb(255, 255, 255); stop-opacity: 0;"
+ offset="1"
+ id="stop2559" />
+ </linearGradient>
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient2555"
+ id="linearGradient2449"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(-0.5914583,0,0,0.5914584,210.0216,142.2324)"
+ x1="-344.15295"
+ y1="274.711"
+ x2="-395.84943"
+ y2="425.39993" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.35"
+ inkscape:cx="-44.119664"
+ inkscape:cy="119.95386"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ inkscape:window-width="853"
+ inkscape:window-height="674"
+ inkscape:window-x="1"
+ inkscape:window-y="281"
+ showgrid="false"
+ inkscape:window-maximized="0" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ <dc:creator>
+ <cc:Agent>
+ <dc:title>User:ZyMOS</dc:title>
+ </cc:Agent>
+ </dc:creator>
+ <dc:subject>
+ <rdf:Bag />
+ </dc:subject>
+ <cc:license
+ rdf:resource="http://creativecommons.org/licenses/publicdomain/" />
+ <dc:description />
+ <dc:contributor>
+ <cc:Agent>
+ <dc:title />
+ </cc:Agent>
+ </dc:contributor>
+ <dc:publisher>
+ <cc:Agent>
+ <dc:title>Open Icon Library</dc:title>
+ </cc:Agent>
+ </dc:publisher>
+ </cc:Work>
+ <cc:License
+ rdf:about="http://creativecommons.org/licenses/publicdomain/">
+ <cc:permits
+ rdf:resource="http://creativecommons.org/ns#Reproduction" />
+ <cc:permits
+ rdf:resource="http://creativecommons.org/ns#Distribution" />
+ <cc:permits
+ rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
+ </cc:License>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-373.642,-318.344)">
+ <rect
+ inkscape:export-ydpi="7.7063322"
+ inkscape:export-xdpi="7.7063322"
+ inkscape:export-filename="C:\Documents and Settings\Molumen\Desktop\path3511111.png"
+ transform="scale(-1,1)"
+ ry="35.487503"
+ rx="35.487503"
+ y="328.84921"
+ x="-619.14587"
+ height="234.98955"
+ width="235.00784"
+ id="rect1942"
+ style="fill:#9dafdf;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.5;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.5,1;stroke-dashoffset:0;stroke-opacity:1" />
+ <path
+ inkscape:export-ydpi="7.7063322"
+ inkscape:export-xdpi="7.7063322"
+ inkscape:export-filename="C:\Documents and Settings\Molumen\Desktop\path3511111.png"
+ sodipodi:nodetypes="ccccsssc"
+ id="path1950"
+ d="M 557.05665,338.89518 L 446.22721,338.89518 C 416.89033,338.89518 393.27256,362.70492 393.27256,392.28025 L 393.27256,500.40761 C 394.22216,523.49366 397.87485,508.89915 404.82758,483.3329 C 412.90814,453.61975 439.22406,427.65003 471.27219,408.1872 C 495.73352,393.33195 523.11328,383.84595 572.95174,382.94353 C 601.21656,382.43177 598.72124,346.26062 557.05665,338.89518 z"
+ style="opacity:1;fill:url(#linearGradient2449);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.87500000000000000;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:0.87500000000000000, 1.75000000000000000;stroke-dashoffset:0;stroke-opacity:1" />
+ <text
+ xml:space="preserve"
+ style="font-size:119.42172241px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;font-family:Georgia;-inkscape-font-specification:Georgia"
+ x="432.28491"
+ y="531.48682"
+ id="text6520"><tspan
+ sodipodi:role="line"
+ id="tspan6522"
+ x="432.28491"
+ y="531.48682"
+ style="font-size:238.84344482px;fill:#ffffff;fill-opacity:1">P</tspan></text>
+ </g>
+</svg>
diff --git a/src-qt5/desktop-utils/lumina-mediaplayer/extra/resources.qrc b/src-qt5/desktop-utils/lumina-mediaplayer/extra/resources.qrc
new file mode 100644
index 00000000..3e09863d
--- /dev/null
+++ b/src-qt5/desktop-utils/lumina-mediaplayer/extra/resources.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource>
+ <file alias="pandora">Pandora.svg</file>
+ </qresource>
+</RCC>
diff --git a/src-qt5/desktop-utils/lumina-mediaplayer/lumina-mediaplayer.pro b/src-qt5/desktop-utils/lumina-mediaplayer/lumina-mediaplayer.pro
index 7d91b770..46286e40 100644
--- a/src-qt5/desktop-utils/lumina-mediaplayer/lumina-mediaplayer.pro
+++ b/src-qt5/desktop-utils/lumina-mediaplayer/lumina-mediaplayer.pro
@@ -1,88 +1,92 @@
include("$${PWD}/../../OS-detect.pri")
-QT += core gui
-greaterThan(QT_MAJOR_VERSION, 4): QT += widgets concurrent
+QT += core gui widgets multimedia multimediawidgets svg
TARGET = lumina-mediaplayer
-TEMPLATE = app
-
-
target.path = $${L_BINDIR}
+TEMPLATE = app
+
#include all the special classes from the Lumina tree
include(../../core/libLumina/LUtils.pri) #includes LUtils
include(../../core/libLumina/LuminaXDG.pri)
+include(../../core/libLumina/LuminaSingleApplication.pri)
+include(../../core/libLumina/LuminaThemes.pri)
SOURCES += main.cpp\
- mainUI.cpp
+ mainUI.cpp \
+ PianoBarProcess.cpp
-HEADERS += mainUI.h
+HEADERS += mainUI.h \
+ PianoBarProcess.h
FORMS += mainUI.ui
-TRANSLATIONS = i18nl-mediap_af.ts \
- i18nl-mediap_ar.ts \
- i18nl-mediap_az.ts \
- i18nl-mediap_bg.ts \
- i18nl-mediap_bn.ts \
- i18nl-mediap_bs.ts \
- i18nl-mediap_ca.ts \
- i18nl-mediap_cs.ts \
- i18nl-mediap_cy.ts \
- i18nl-mediap_da.ts \
- i18nl-mediap_de.ts \
- i18nl-mediap_el.ts \
- i18nl-mediap_en_GB.ts \
- i18nl-mediap_en_ZA.ts \
- i18nl-mediap_es.ts \
- i18nl-mediap_et.ts \
- i18nl-mediap_eu.ts \
- i18nl-mediap_fa.ts \
- i18nl-mediap_fi.ts \
- i18nl-mediap_fr.ts \
- i18nl-mediap_fr_CA.ts \
- i18nl-mediap_gl.ts \
- i18nl-mediap_he.ts \
- i18nl-mediap_hi.ts \
- i18nl-mediap_hr.ts \
- i18nl-mediap_hu.ts \
- i18nl-mediap_id.ts \
- i18nl-mediap_is.ts \
- i18nl-mediap_it.ts \
- i18nl-mediap_ja.ts \
- i18nl-mediap_ka.ts \
- i18nl-mediap_ko.ts \
- i18nl-mediap_lt.ts \
- i18nl-mediap_lv.ts \
- i18nl-mediap_mk.ts \
- i18nl-mediap_mn.ts \
- i18nl-mediap_ms.ts \
- i18nl-mediap_mt.ts \
- i18nl-mediap_nb.ts \
- i18nl-mediap_nl.ts \
- i18nl-mediap_pa.ts \
- i18nl-mediap_pl.ts \
- i18nl-mediap_pt.ts \
- i18nl-mediap_pt_BR.ts \
- i18nl-mediap_ro.ts \
- i18nl-mediap_ru.ts \
- i18nl-mediap_sk.ts \
- i18nl-mediap_sl.ts \
- i18nl-mediap_sr.ts \
- i18nl-mediap_sv.ts \
- i18nl-mediap_sw.ts \
- i18nl-mediap_ta.ts \
- i18nl-mediap_tg.ts \
- i18nl-mediap_th.ts \
- i18nl-mediap_tr.ts \
- i18nl-mediap_uk.ts \
- i18nl-mediap_uz.ts \
- i18nl-mediap_vi.ts \
- i18nl-mediap_zh_CN.ts \
- i18nl-mediap_zh_HK.ts \
- i18nl-mediap_zh_TW.ts \
- i18nl-mediap_zu.ts
+RESOURCES += extra/resources.qrc
+
+TRANSLATIONS = i18n/l-mediap_af.ts \
+ i18n/l-mediap_ar.ts \
+ i18n/l-mediap_az.ts \
+ i18n/l-mediap_bg.ts \
+ i18n/l-mediap_bn.ts \
+ i18n/l-mediap_bs.ts \
+ i18n/l-mediap_ca.ts \
+ i18n/l-mediap_cs.ts \
+ i18n/l-mediap_cy.ts \
+ i18n/l-mediap_da.ts \
+ i18n/l-mediap_de.ts \
+ i18n/l-mediap_el.ts \
+ i18n/l-mediap_en_GB.ts \
+ i18n/l-mediap_en_ZA.ts \
+ i18n/l-mediap_es.ts \
+ i18n/l-mediap_et.ts \
+ i18n/l-mediap_eu.ts \
+ i18n/l-mediap_fa.ts \
+ i18n/l-mediap_fi.ts \
+ i18n/l-mediap_fr.ts \
+ i18n/l-mediap_fr_CA.ts \
+ i18n/l-mediap_gl.ts \
+ i18n/l-mediap_he.ts \
+ i18n/l-mediap_hi.ts \
+ i18n/l-mediap_hr.ts \
+ i18n/l-mediap_hu.ts \
+ i18n/l-mediap_id.ts \
+ i18n/l-mediap_is.ts \
+ i18n/l-mediap_it.ts \
+ i18n/l-mediap_ja.ts \
+ i18n/l-mediap_ka.ts \
+ i18n/l-mediap_ko.ts \
+ i18n/l-mediap_lt.ts \
+ i18n/l-mediap_lv.ts \
+ i18n/l-mediap_mk.ts \
+ i18n/l-mediap_mn.ts \
+ i18n/l-mediap_ms.ts \
+ i18n/l-mediap_mt.ts \
+ i18n/l-mediap_nb.ts \
+ i18n/l-mediap_nl.ts \
+ i18n/l-mediap_pa.ts \
+ i18n/l-mediap_pl.ts \
+ i18n/l-mediap_pt.ts \
+ i18n/l-mediap_pt_BR.ts \
+ i18n/l-mediap_ro.ts \
+ i18n/l-mediap_ru.ts \
+ i18n/l-mediap_sk.ts \
+ i18n/l-mediap_sl.ts \
+ i18n/l-mediap_sr.ts \
+ i18n/l-mediap_sv.ts \
+ i18n/l-mediap_sw.ts \
+ i18n/l-mediap_ta.ts \
+ i18n/l-mediap_tg.ts \
+ i18n/l-mediap_th.ts \
+ i18n/l-mediap_tr.ts \
+ i18n/l-mediap_uk.ts \
+ i18n/l-mediap_uz.ts \
+ i18n/l-mediap_vi.ts \
+ i18n/l-mediap_zh_CN.ts \
+ i18n/l-mediap_zh_HK.ts \
+ i18n/l-mediap_zh_TW.ts \
+ i18n/l-mediap_zu.ts
dotrans.path=$${L_SHAREDIR}/lumina-desktop/i18n/
dotrans.extra=cd i18n && $${LRELEASE} -nounfinished *.ts && cp *.qm $(INSTALL_ROOT)$${L_SHAREDIR}/lumina-desktop/i18n/
diff --git a/src-qt5/desktop-utils/lumina-mediaplayer/main.cpp b/src-qt5/desktop-utils/lumina-mediaplayer/main.cpp
new file mode 100644
index 00000000..9eebff9f
--- /dev/null
+++ b/src-qt5/desktop-utils/lumina-mediaplayer/main.cpp
@@ -0,0 +1,30 @@
+//===========================================
+// Lumina-DE source code
+// Copyright (c) 2016, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#include <QApplication>
+#include <QDebug>
+
+#include <LuminaThemes.h>
+#include <LUtils.h>
+#include <LuminaSingleApplication.h>
+
+#include "mainUI.h"
+
+int main(int argc, char *argv[]) {
+ LTHEME::LoadCustomEnvSettings();
+ LSingleApplication a(argc, argv, "l-mediap");
+ //Now go ahead and setup the app
+ QStringList args;
+ for(int i=1; i<argc; i++){
+ if( QString(argv[i]).startsWith("--") ){ args << QString(argv[i]); }
+ else{ args << LUtils::PathToAbsolute( QString(argv[i]) ); }
+ }
+ //Now start the window
+ MainUI W;
+ W.loadArguments(args);
+ W.show();
+ return a.exec();
+}
diff --git a/src-qt5/desktop-utils/lumina-mediaplayer/mainUI.cpp b/src-qt5/desktop-utils/lumina-mediaplayer/mainUI.cpp
new file mode 100644
index 00000000..967687be
--- /dev/null
+++ b/src-qt5/desktop-utils/lumina-mediaplayer/mainUI.cpp
@@ -0,0 +1,341 @@
+//===========================================
+// Lumina-Desktop source code
+// Copyright (c) 2017, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#include "mainUI.h"
+#include "ui_mainUI.h"
+#include <QDebug>
+
+#include <LuminaXDG.h>
+#include <QDesktopServices>
+#include <QUrl>
+
+MainUI::MainUI() : QMainWindow(), ui(new Ui::MainUI()){
+ ui->setupUi(this);
+ closing = false;
+ //Any special UI changes
+ QWidget *spacer = new QWidget(this);
+ spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+ ui->toolBar->insertWidget(ui->actionVolUp, spacer);
+ //Setup an action group for the various modes/streams
+ QButtonGroup *grp = new QButtonGroup(this);
+ grp->addButton(ui->radio_local);
+ grp->addButton(ui->radio_pandora);
+ grp->setExclusive(true);
+ setupPandora();
+ ui->radio_pandora->setChecked(true);
+ setupTrayIcon();
+ setupConnections();
+ setupIcons();
+ PlayerTypeChanged();
+ SYSTRAY->show();
+}
+
+MainUI::~MainUI(){
+
+}
+
+void MainUI::loadArguments(QStringList){
+
+}
+
+
+// ==== PRIVATE ====
+void MainUI::setupPandora(){
+ PANDORA = new PianoBarProcess(this);
+ connect(PANDORA, SIGNAL(currentStateChanged(PianoBarProcess::State)), this, SLOT(PandoraStateChanged(PianoBarProcess::State)) );
+ connect(PANDORA, SIGNAL(NewInformation(QString)), this, SLOT(NewPandoraInfo(QString)) );
+ connect(PANDORA, SIGNAL(NowPlayingStation(QString, QString)), this, SLOT(PandoraStationChanged(QString)) );
+ connect(PANDORA, SIGNAL(NowPlayingSong(bool, QString,QString,QString, QString, QString)), this, SLOT(PandoraSongChanged(bool, QString, QString, QString, QString, QString)) );
+ connect(PANDORA, SIGNAL(TimeUpdate(int, int)), this, SLOT(PandoraTimeUpdate(int,int)) );
+ connect(PANDORA, SIGNAL(NewList(QStringList)), this, SLOT(PandoraListInfo(QStringList)) );
+ connect(PANDORA, SIGNAL(StationListChanged(QStringList)), this, SLOT(PandoraStationListChanged(QStringList)) );
+ //Setup a couple of the option lists
+ ui->combo_pandora_quality->clear();
+ ui->combo_pandora_quality->addItem(tr("Low"),"low");
+ ui->combo_pandora_quality->addItem(tr("Medium"), "medium");
+ ui->combo_pandora_quality->addItem(tr("High"),"high");
+ //Now load the current settings into the UI
+ int qual = ui->combo_pandora_quality->findData(PANDORA->audioQuality());
+ if(qual>=0){ ui->combo_pandora_quality->setCurrentIndex(qual); }
+ else{ ui->combo_pandora_quality->setCurrentIndex(1); } //medium quality by default
+ ui->line_pandora_email->setText( PANDORA->email() );
+ ui->line_pandora_pass->setText( PANDORA->password() );
+ ui->line_pandora_proxy->setText( PANDORA->proxy() );
+ ui->line_pandora_cproxy->setText( PANDORA->controlProxy() );
+ //Make sure the interface is enabled/disabled as needed
+ PandoraStateChanged(PANDORA->currentState());
+ ui->progress_pandora->setRange(0,1);
+ ui->progress_pandora->setValue(0);
+
+ //Setup the menu for new stations
+ QMenu *tmp = new QMenu(this);
+ tmp->addAction(ui->action_pandora_newstation_song);
+ tmp->addAction(ui->action_pandora_newstation_artist);
+ ui->tool_pandora_stationadd->setMenu( tmp );
+
+}
+
+void MainUI::setupConnections(){
+ connect(ui->radio_local, SIGNAL(toggled(bool)), this, SLOT(PlayerTypeChanged(bool)) );
+ connect(ui->radio_pandora, SIGNAL(toggled(bool)), this, SLOT(PlayerTypeChanged(bool)) );
+
+ connect(ui->actionPlay, SIGNAL(triggered()), this, SLOT(playToggled()) );
+ connect(ui->actionPause, SIGNAL(triggered()), this, SLOT(pauseToggled()) );
+ connect(ui->actionStop, SIGNAL(triggered()), this, SLOT(stopToggled()) );
+ connect(ui->actionNext, SIGNAL(triggered()), this, SLOT(nextToggled()) );
+ connect(ui->actionBack, SIGNAL(triggered()), this, SLOT(backToggled()) );
+ connect(ui->actionVolUp, SIGNAL(triggered()), this, SLOT(volupToggled()) );
+ connect(ui->actionVolDown, SIGNAL(triggered()), this, SLOT(voldownToggled()) );
+ connect(ui->actionClose, SIGNAL(triggered()), this, SLOT(closeApplication()) );
+
+ connect(ui->push_pandora_apply, SIGNAL(clicked()), this, SLOT(applyPandoraSettings()) );
+ connect(ui->combo_pandora_station, SIGNAL(activated(QString)), this, SLOT(changePandoraStation(QString)) );
+ connect(ui->tool_pandora_ban, SIGNAL(clicked()), PANDORA, SLOT(banSong()) );
+ connect(ui->tool_pandora_love, SIGNAL(clicked()), PANDORA, SLOT(loveSong()) );
+ connect(ui->tool_pandora_tired, SIGNAL(clicked()), PANDORA, SLOT(tiredSong()) );
+ connect(ui->tool_pandora_info, SIGNAL(clicked()), this, SLOT(showPandoraSongInfo()) );
+ connect(ui->tool_pandora_stationrm, SIGNAL(clicked()), PANDORA, SLOT(deleteCurrentStation()) );
+ connect(ui->action_pandora_newstation_artist, SIGNAL(triggered()), PANDORA, SLOT(createStationFromCurrentArtist()) );
+ connect(ui->action_pandora_newstation_song, SIGNAL(triggered()), PANDORA, SLOT(createStationFromCurrentSong()) );
+
+ connect(SYSTRAY, SIGNAL(activated(QSystemTrayIcon::ActivationReason)), this, SLOT(trayClicked(QSystemTrayIcon::ActivationReason)) );
+ connect(SYSTRAY, SIGNAL(messageClicked()), this, SLOT(showNormal()) );
+}
+
+void MainUI::setupIcons(){
+ ui->actionClose->setIcon( LXDG::findIcon("application-close","dialog-close") );
+ ui->actionPlay->setIcon( LXDG::findIcon("media-playback-start","") );
+ ui->actionPause->setIcon( LXDG::findIcon("media-playback-pause","") );
+ ui->actionStop->setIcon( LXDG::findIcon("media-playback-stop","") );
+ ui->actionNext->setIcon( LXDG::findIcon("media-skip-forward","") );
+ ui->actionBack->setIcon( LXDG::findIcon("media-skip-backward","") );
+
+ //Pandora Pages
+ ui->push_pandora_apply->setIcon( LXDG::findIcon("dialog-ok-apply","dialog-ok") );
+ ui->tool_pandora_ban->setIcon( LXDG::findIcon("dialog-cancel","") );
+ ui->tool_pandora_info->setIcon( LXDG::findIcon("help-about","") );
+ ui->tool_pandora_love->setIcon( LXDG::findIcon("emblem-favorite","") );
+ ui->tool_pandora_tired->setIcon( LXDG::findIcon("flag-yellow","flag") );
+ ui->tool_pandora_stationrm->setIcon( LXDG::findIcon("list-remove","") );
+ ui->tool_pandora_stationadd->setIcon( LXDG::findIcon("list-add","") );
+ ui->action_pandora_newstation_artist->setIcon( LXDG::findIcon("list-add-user","") );
+ ui->action_pandora_newstation_song->setIcon( LXDG::findIcon("audio-x-generic","") );
+
+}
+
+void MainUI::setupTrayIcon(){
+ SYSTRAY = new QSystemTrayIcon(this);
+ QMenu *tmp = new QMenu(this);
+ SYSTRAY->setContextMenu(tmp);
+ tmp->addAction(ui->actionPlay);
+ tmp->addAction(ui->actionPause);
+ tmp->addAction(ui->actionStop);
+ tmp->addAction(ui->actionBack);
+ tmp->addAction(ui->actionNext);
+ tmp->addSeparator();
+ tmp->addAction(ui->actionClose);
+}
+
+void MainUI::closeTrayIcon(){
+
+}
+
+// ==== PRIVATE SLOTS ====
+void MainUI::closeApplication(){
+ closing = true;
+ if(PANDORA->currentState()!= PianoBarProcess::Stopped){
+ PANDORA->closePianoBar();
+ this->hide();
+ QTimer::singleShot(500, this, SLOT(close()) );
+ }else{
+ this->close();
+ }
+}
+
+void MainUI::PlayerTypeChanged(bool active){
+ if(!active){ return; } //this gets rid of the "extra" signals from the radio button functionality (1 signal from each button on change)
+ if(ui->radio_pandora->isChecked()){
+ ui->stackedWidget->setCurrentWidget(ui->page_pandora);
+ PandoraStateChanged(PANDORA->currentState());
+ SYSTRAY->setIcon( QIcon(":pandora") );
+ this->setWindowIcon( QIcon(":pandora") );
+ this->setWindowTitle( tr("Pandora Radio") );
+ }else{
+ ui->stackedWidget->setCurrentWidget(ui->page_local);
+ SYSTRAY->setIcon( LXDG::findIcon("audio-x-generic","") );
+ this->setWindowIcon( LXDG::findIcon("audio-x-generic","") );
+ this->setWindowTitle( tr("Media Player") );
+ }
+ //Now close down any currently running streams as needed
+ if(!ui->radio_pandora->isChecked() && PANDORA->currentState()!=PianoBarProcess::Stopped){ PANDORA->closePianoBar(); }
+
+ //Now hide/deactivate any toolbar buttons which are not used
+ ui->actionBack->setVisible(!ui->radio_pandora->isChecked());
+}
+
+
+//Toolbar actions
+void MainUI::playToggled(){
+ if(ui->radio_pandora->isChecked()){
+ PANDORA->play();
+ }
+}
+
+void MainUI::pauseToggled(){
+ if(ui->radio_pandora->isChecked()){
+ PANDORA->pause();
+ }
+}
+
+void MainUI::stopToggled(){
+ if(ui->radio_pandora->isChecked()){
+ PANDORA->closePianoBar();
+ }
+}
+
+void MainUI::nextToggled(){
+ if(ui->radio_pandora->isChecked()){
+ PANDORA->skipSong();
+ }
+}
+
+void MainUI::backToggled(){
+
+}
+
+void MainUI::volupToggled(){
+
+}
+
+void MainUI::voldownToggled(){
+
+}
+
+
+//Pandora Options
+void MainUI::showPandoraSongInfo(){
+ QDesktopServices::openUrl( QUrl(ui->tool_pandora_info->whatsThis()) );
+}
+
+void MainUI::changePandoraStation(QString station){
+ if(station == PANDORA->currentStation()){ return; }
+ qDebug() << "[CHANGE STATION]" << station << "from:" << PANDORA->currentStation();
+ PANDORA->setCurrentStation(station);
+}
+
+void MainUI::applyPandoraSettings(){
+ PANDORA->setLogin(ui->line_pandora_email->text(), ui->line_pandora_pass->text());
+ PANDORA->setAudioQuality(ui->combo_pandora_quality->currentData().toString());
+ PANDORA->setProxy(ui->line_pandora_proxy->text());
+ PANDORA->setControlProxy(ui->line_pandora_cproxy->text());
+}
+
+//Pandora Process Feedback
+void MainUI::PandoraStateChanged(PianoBarProcess::State state){
+ //qDebug() << "[STATE CHANGE]" << state;
+ ui->actionPlay->setVisible(state != PianoBarProcess::Running);
+ ui->actionPause->setVisible(state == PianoBarProcess::Running);
+ ui->actionStop->setVisible(state != PianoBarProcess::Stopped);
+ ui->actionBack->setVisible(false); //never available for Pandora streams
+ ui->actionNext->setVisible(state!=PianoBarProcess::Stopped);
+ ui->tabWidget_pandora->setTabEnabled(0, state !=PianoBarProcess::Stopped);
+ if(!ui->tabWidget_pandora->isTabEnabled(0) && ui->tabWidget_pandora->currentIndex()==0){
+ ui->tabWidget_pandora->setCurrentWidget(ui->tab_pandora_settings);
+ }else if(state == PianoBarProcess::Running){
+ ui->tabWidget_pandora->setCurrentWidget(ui->tab_pandora_playing);
+ }
+}
+
+void MainUI::NewPandoraInfo(QString info){
+ //qDebug() << "[INFO]" << info;
+ ui->statusbar->showMessage(info, 2000);
+}
+
+void MainUI::PandoraStationChanged(QString station){
+ qDebug() << "[STATION CHANGE]" << station;
+ int index = ui->combo_pandora_station->findText( station );
+ if(index>=0){
+ qDebug() <<" [FOUND]" << ui->combo_pandora_station->itemText(index);
+ ui->combo_pandora_station->setCurrentIndex(index);
+ }else{
+ //Could not find the station in the current list - need to update that first
+ qDebug() <<" [NOT FOUND]";
+ PandoraStationListChanged(PANDORA->stations());
+ }
+}
+
+void MainUI::PandoraSongChanged(bool isLoved, QString title, QString artist, QString album, QString detailsURL, QString fromStation){
+ //qDebug() << "[SONG CHANGE]" << isLoved << title << artist << album << detailsURL << fromStation;
+ ui->tool_pandora_info->setWhatsThis(detailsURL);
+ ui->tool_pandora_love->setChecked(isLoved);
+ ui->tool_pandora_love->setEnabled(!isLoved); //pianobar cannot "unlove" a song
+ ui->label_pandora_album->setText(album);
+ ui->label_pandora_artist->setText(artist);
+ ui->label_pandora_title->setText(title);
+ ui->progress_pandora->setRange(0,1);
+ ui->progress_pandora->setValue(0);
+ ui->progress_pandora->setFormat("");
+ if(ui->action_showNotifications->isChecked()){
+ QString msg = QString(tr("%1\nBy %2 on %3")).arg(title, artist, album);
+ SYSTRAY->showMessage(tr("Now Playing"), msg, QSystemTrayIcon::NoIcon, 1500); //1.5 seconds
+ }
+}
+
+void MainUI::PandoraTimeUpdate(int curS, int totS){
+ //qDebug() << "[TIME UPDATE]" << curS << "/" << totS;
+ ui->progress_pandora->setRange(0, totS);
+ ui->progress_pandora->setValue(curS);
+ QString time = QTime(0, curS/60, curS%60,0).toString("m:ss") + "/" + QTime(0, totS/60, totS%60,0).toString("m:ss");
+ ui->progress_pandora->setFormat(time);
+}
+
+void MainUI::PandoraStationListChanged(QStringList list){
+ qDebug() << "[STATION LIST]" << list;
+ ui->combo_pandora_station->clear();
+ if(list.isEmpty()){ return; }
+ ui->combo_pandora_station->addItems(list);
+ int index = ui->combo_pandora_station->findText( PANDORA->currentStation() );
+ qDebug() << "[CURRENT STATION]" << PANDORA->currentStation() << index;
+ if(index>=0){ ui->combo_pandora_station->setCurrentIndex(index); }
+}
+
+void MainUI::PandoraListInfo(QStringList list){
+ qDebug() << "[LIST INFO]" << list;
+}
+
+//System Tray interactions
+void MainUI::toggleVisibility(){
+ if(this->isVisible()){ this->hide(); }
+ else{ this->showNormal(); }
+}
+
+void MainUI::trayClicked(QSystemTrayIcon::ActivationReason rsn){
+ if(rsn == QSystemTrayIcon::Context){
+ SYSTRAY->contextMenu()->popup(QCursor::pos());
+ }else{
+ toggleVisibility();
+ }
+}
+
+void MainUI::closeEvent(QCloseEvent *ev){
+ if(!closing){
+ //Check if we have audio playing to determine if we should just minimize instead
+ if(ui->action_closeToTray->isChecked()){
+ closing = (PANDORA->currentState()!=PianoBarProcess::Running);
+ }else if(PANDORA->currentState()!=PianoBarProcess::Stopped){
+ //Make sure we close the stream down first
+ PANDORA->closePianoBar();
+ QTimer::singleShot(500, this, SLOT(close()) ); //try again in a moment
+ }else{
+ closing = true;
+ }
+ }
+ if(closing){ QMainWindow::closeEvent(ev); } //normal close procedure
+ else{
+ ev->ignore();
+ this->hide();
+ }
+}
diff --git a/src-qt5/desktop-utils/lumina-mediaplayer/mainUI.h b/src-qt5/desktop-utils/lumina-mediaplayer/mainUI.h
new file mode 100644
index 00000000..a545eda3
--- /dev/null
+++ b/src-qt5/desktop-utils/lumina-mediaplayer/mainUI.h
@@ -0,0 +1,77 @@
+//===========================================
+// Lumina-Desktop source code
+// Copyright (c) 2017, Ken Moore
+// Available under the 3-clause BSD license
+// See the LICENSE file for full details
+//===========================================
+#ifndef _LUMINA_MEDIA_PLAYER_MAIN_UI_H
+#define _LUMINA_MEDIA_PLAYER_MAIN_UI_H
+
+#include <QMainWindow>
+#include <QAction>
+#include <QString>
+#include <QStringList>
+#include <QSystemTrayIcon>
+#include <QCloseEvent>
+
+#include "PianoBarProcess.h"
+
+namespace Ui{
+ class MainUI;
+};
+
+class MainUI : public QMainWindow{
+ Q_OBJECT
+public:
+ MainUI();
+ ~MainUI();
+
+ void loadArguments(QStringList);
+
+private:
+ Ui::MainUI *ui;
+ PianoBarProcess *PANDORA;
+ QSystemTrayIcon *SYSTRAY;
+ bool closing;
+
+ void setupPandora();
+ void setupConnections();
+ void setupIcons();
+ void setupTrayIcon();
+ void closeTrayIcon();
+
+private slots:
+ void closeApplication();
+ void PlayerTypeChanged(bool active = true);
+
+ //Toolbar actions
+ void playToggled();
+ void pauseToggled();
+ void stopToggled();
+ void nextToggled();
+ void backToggled();
+ void volupToggled();
+ void voldownToggled();
+
+ //Pandora Options
+ void showPandoraSongInfo();
+ void changePandoraStation(QString);
+ void applyPandoraSettings();
+ //Pandora Process Feedback
+ void PandoraStateChanged(PianoBarProcess::State);
+ void NewPandoraInfo(QString);
+ void PandoraStationChanged(QString);
+ void PandoraSongChanged(bool, QString, QString, QString, QString, QString); //[isLoved, title, artist, album, detailsURL, fromStation]
+ void PandoraTimeUpdate(int,int); //current secs, total secs
+ void PandoraStationListChanged(QStringList);
+ void PandoraListInfo(QStringList);
+
+ //System Tray interactions
+ void toggleVisibility();
+ void trayClicked(QSystemTrayIcon::ActivationReason);
+
+protected:
+ void closeEvent(QCloseEvent *ev);
+
+};
+#endif
diff --git a/src-qt5/desktop-utils/lumina-mediaplayer/mainUI.ui b/src-qt5/desktop-utils/lumina-mediaplayer/mainUI.ui
index d662b20c..e00d3c90 100644
--- a/src-qt5/desktop-utils/lumina-mediaplayer/mainUI.ui
+++ b/src-qt5/desktop-utils/lumina-mediaplayer/mainUI.ui
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
- <class>MainWindow</class>
- <widget class="QMainWindow" name="MainWindow">
+ <class>MainUI</class>
+ <widget class="QMainWindow" name="MainUI">
<property name="geometry">
<rect>
<x>0</x>
@@ -11,7 +11,7 @@
</rect>
</property>
<property name="windowTitle">
- <string>MainWindow</string>
+ <string>Media Player</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout">
@@ -33,18 +33,46 @@
<item>
<widget class="QFrame" name="frame_type">
<layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="topMargin">
+ <number>1</number>
+ </property>
+ <property name="bottomMargin">
+ <number>1</number>
+ </property>
<item>
- <widget class="QRadioButton" name="radio_local">
+ <widget class="QToolButton" name="radio_local">
<property name="text">
<string>Local Files</string>
</property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
</widget>
</item>
<item>
- <widget class="QRadioButton" name="radio_pandora">
+ <widget class="QToolButton" name="radio_pandora">
<property name="text">
<string>Pandora Radio</string>
</property>
+ <property name="icon">
+ <iconset resource="extra/resources.qrc">
+ <normaloff>:/pandora</normaloff>:/pandora</iconset>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="toolButtonStyle">
+ <enum>Qt::ToolButtonTextBesideIcon</enum>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
</widget>
</item>
</layout>
@@ -52,11 +80,14 @@
</item>
<item>
<widget class="QStackedWidget" name="stackedWidget">
+ <property name="currentIndex">
+ <number>1</number>
+ </property>
<widget class="QWidget" name="page_local"/>
<widget class="QWidget" name="page_pandora">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
- <widget class="QTabWidget" name="tabWidget">
+ <widget class="QTabWidget" name="tabWidget_pandora">
<property name="currentIndex">
<number>0</number>
</property>
@@ -64,11 +95,374 @@
<attribute name="title">
<string>Now Playing</string>
</attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_5">
+ <item>
+ <widget class="QGroupBox" name="groupBox_2">
+ <property name="title">
+ <string>Current Song</string>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <property name="spacing">
+ <number>1</number>
+ </property>
+ <property name="leftMargin">
+ <number>2</number>
+ </property>
+ <property name="topMargin">
+ <number>2</number>
+ </property>
+ <property name="rightMargin">
+ <number>2</number>
+ </property>
+ <property name="bottomMargin">
+ <number>2</number>
+ </property>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_4">
+ <item>
+ <widget class="QLabel" name="label_pandora_title">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>10</pointsize>
+ <weight>75</weight>
+ <bold>true</bold>
+ </font>
+ </property>
+ <property name="text">
+ <string>TITLE</string>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ <property name="openExternalLinks">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_pandora_artist">
+ <property name="font">
+ <font>
+ <italic>true</italic>
+ </font>
+ </property>
+ <property name="text">
+ <string>ARTIST</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_pandora_album">
+ <property name="text">
+ <string>ALBUM</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QProgressBar" name="progress_pandora">
+ <property name="value">
+ <number>24</number>
+ </property>
+ <property name="format">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="Line" name="line_2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <item>
+ <widget class="QToolButton" name="tool_pandora_love">
+ <property name="statusTip">
+ <string>Love this song</string>
+ </property>
+ <property name="text">
+ <string notr="true">love</string>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="tool_pandora_tired">
+ <property name="statusTip">
+ <string>Tired of this song (will not play for a month)</string>
+ </property>
+ <property name="text">
+ <string notr="true">tired</string>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="tool_pandora_ban">
+ <property name="statusTip">
+ <string>Ban this song (will never play again)</string>
+ </property>
+ <property name="text">
+ <string notr="true">ban</string>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="Line" name="line">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="tool_pandora_info">
+ <property name="statusTip">
+ <string>View details about song (launches web browser)</string>
+ </property>
+ <property name="text">
+ <string notr="true">info</string>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_4">
+ <item>
+ <widget class="QLabel" name="label_6">
+ <property name="text">
+ <string>Current Station</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="combo_pandora_station"/>
+ </item>
+ <item>
+ <widget class="QToolButton" name="tool_pandora_stationrm">
+ <property name="statusTip">
+ <string>Delete current station</string>
+ </property>
+ <property name="text">
+ <string>rm</string>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="tool_pandora_stationadd">
+ <property name="statusTip">
+ <string>Create new station</string>
+ </property>
+ <property name="text">
+ <string>add</string>
+ </property>
+ <property name="popupMode">
+ <enum>QToolButton::InstantPopup</enum>
+ </property>
+ <property name="autoRaise">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
</widget>
<widget class="QWidget" name="tab_pandora_settings">
<attribute name="title">
<string>Settings</string>
</attribute>
+ <layout class="QFormLayout" name="formLayout_2">
+ <property name="labelAlignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ <item row="0" column="0" colspan="2">
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>Pandora Account Login</string>
+ </property>
+ <layout class="QFormLayout" name="formLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Email</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QLineEdit" name="line_pandora_email"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Password</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLineEdit" name="line_pandora_pass">
+ <property name="echoMode">
+ <enum>QLineEdit::Password</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLabel" name="label_7">
+ <property name="font">
+ <font>
+ <pointsize>8</pointsize>
+ <italic>true</italic>
+ </font>
+ </property>
+ <property name="text">
+ <string>&lt;a href=https://www.pandora.com/account/register&gt;Need an account?&lt;/a&gt;</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ <property name="openExternalLinks">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Audio Quality</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QComboBox" name="combo_pandora_quality"/>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>Proxy URL</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QLineEdit" name="line_pandora_proxy"/>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="label_5">
+ <property name="text">
+ <string>Control Proxy URL</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QLineEdit" name="line_pandora_cproxy"/>
+ </item>
+ <item row="5" column="0" colspan="2">
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="push_pandora_apply">
+ <property name="text">
+ <string>Apply Settings</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item row="4" column="0">
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
</widget>
</widget>
</item>
@@ -84,9 +478,25 @@
<x>0</x>
<y>0</y>
<width>385</width>
- <height>22</height>
+ <height>20</height>
</rect>
</property>
+ <widget class="QMenu" name="menuFile">
+ <property name="title">
+ <string>File</string>
+ </property>
+ <addaction name="separator"/>
+ <addaction name="actionClose"/>
+ </widget>
+ <widget class="QMenu" name="menuView">
+ <property name="title">
+ <string>View</string>
+ </property>
+ <addaction name="action_closeToTray"/>
+ <addaction name="action_showNotifications"/>
+ </widget>
+ <addaction name="menuFile"/>
+ <addaction name="menuView"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<widget class="QToolBar" name="toolBar">
@@ -151,7 +561,58 @@
<string>VolDown</string>
</property>
</action>
+ <action name="actionClose">
+ <property name="text">
+ <string>Close Application</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+Q</string>
+ </property>
+ <property name="shortcutContext">
+ <enum>Qt::ApplicationShortcut</enum>
+ </property>
+ </action>
+ <action name="action_closeToTray">
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Close to tray when active</string>
+ </property>
+ </action>
+ <action name="action_pandora_newstation_artist">
+ <property name="text">
+ <string>From current artist</string>
+ </property>
+ <property name="statusTip">
+ <string>Create station from current artist</string>
+ </property>
+ </action>
+ <action name="action_pandora_newstation_song">
+ <property name="text">
+ <string>From current song</string>
+ </property>
+ <property name="statusTip">
+ <string>Create station from current song</string>
+ </property>
+ </action>
+ <action name="action_showNotifications">
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Show song notifications</string>
+ </property>
+ </action>
</widget>
- <resources/>
+ <resources>
+ <include location="extra/resources.qrc"/>
+ </resources>
<connections/>
</ui>
bgstack15