diff options
Diffstat (limited to 'src-qt5/desktop-utils')
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><a href=https://www.pandora.com/account/register>Need an account?</a></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> |