/* * Copyright (C) 2017 Kevin Whitaker * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * */ #include "PlayerInterface.h" #include #include "../GroovePlayer.h" #include #include #include #include #include PlayerInterface::PlayerInterface(WebInterface* app) { this->app = app; interfaceLayout = new Wt::WVBoxLayout(); this->setLayout(interfaceLayout); playControlLayout = new Wt::WHBoxLayout(); playControlWidget = new Wt::WContainerWidget(); skipControls = new Wt::WContainerWidget(); playControlWidget->setLayout(playControlLayout); currentTrackProgress = new Wt::WProgressBar(); currentTrackProgress->setFormat(""); trackProgress = new Wt::WTimer(); trackProgress->setInterval(1000); trackProgress->timeout().connect(this,&PlayerInterface::updateProgressFromTimer); currentTrackDetails = new TrackDetails(); currentTrackDetails->setMinimumSize(Wt::WLength(100,Wt::WLength::Pixel),Wt::WLength(100,Wt::WLength::Pixel)); currentTrackDetails->changeBackgroundColor(Wt::WColor("#6FFF6F")); playpause = new Wt::WPushButton(); playpause->setTextFormat(Wt::XHTMLText); playpause->decorationStyle().font().setFamily(Wt::WFont::Default,"FontAwesome"); playpause->setText(groove_playlist_playing(GroovePlayerMgr::getInstance()->currentPlaylist)==1?Wt::WString::fromUTF8(""):Wt::WString::fromUTF8("")); playpause->setMaximumSize(Wt::WLength(60,Wt::WLength::Point),Wt::WLength(30,Wt::WLength::Point)); isPaused = groove_playlist_playing(GroovePlayerMgr::getInstance()->currentPlaylist)==0; playpause->clicked().connect(this, &PlayerInterface::playpauseClicked); skipRequest = new Wt::WPushButton(); skipRequest->clicked().connect(this, &PlayerInterface::skipRequestClicked); skipRequest->setTextFormat(Wt::XHTMLText); skipRequest->decorationStyle().font().setFamily(Wt::WFont::Default,"FontAwesome"); skipRequest->setText(""); skipDeny = new Wt::WPushButton(); skipDeny->clicked().connect(this, &PlayerInterface::skipDenyClicked); skipDeny->setTextFormat(Wt::XHTMLText); skipDeny->decorationStyle().font().setFamily(Wt::WFont::Default,"FontAwesome"); skipDeny->setText(""); skipDeny->setHidden(true); skipControls->addWidget(skipRequest); skipControls->addWidget(skipDeny); mainDisplay = new Wt::WTabWidget(); requestPane = new RequestInterface(app); voteMetaContainer = new Wt::WContainerWidget(); voteMetaLayout = new Wt::WVBoxLayout(); voteMetaContainer->setLayout(voteMetaLayout); voteControlContainer = new Wt::WContainerWidget(); voteControlContainer->setMaximumSize(Wt::WLength(75,Wt::WLength::Percentage),Wt::WLength::Auto); votePanel = new Wt::WPanel(); votePanel->addStyleClass("panel-primary"); voteTracksContainer = new Wt::WContainerWidget(); voteTracksContainer->addStyleClass("panel-body"); voteTracksLayout = new Wt::WVBoxLayout(); track1 = new Wt::WHBoxLayout(); track1details = new TrackDetails(); track1details->changeBackgroundColor(Wt::WColor("gainsboro")); track1vote = new Wt::WPushButton(); track1vote->setTextFormat(Wt::XHTMLText); track1vote->decorationStyle().font().setFamily(Wt::WFont::Default,"FontAwesome"); track1vote->setMaximumSize(Wt::WLength(50,Wt::WLength::Pixel),Wt::WLength(50,Wt::WLength::Pixel)); track1vote->setText(""); track1votecount = new Wt::WText("0"); track1->addWidget(track1details,1,Wt::AlignmentFlag::AlignMiddle | Wt::AlignmentFlag::AlignLeft); track1->addWidget(track1vote,0,Wt::AlignmentFlag::AlignMiddle | Wt::AlignmentFlag::AlignRight); track1->addWidget(track1votecount,0,Wt::AlignmentFlag::AlignMiddle | Wt::AlignmentFlag::AlignLeft); track2 = new Wt::WHBoxLayout(); track2details = new TrackDetails(); track2details->changeBackgroundColor(Wt::WColor("gainsboro")); track2vote = new Wt::WPushButton(); track2vote->setTextFormat(Wt::XHTMLText); track2vote->decorationStyle().font().setFamily(Wt::WFont::Default,"FontAwesome"); track2vote->setMaximumSize(Wt::WLength(50,Wt::WLength::Pixel),Wt::WLength(50,Wt::WLength::Pixel)); track2vote->setText(""); track2votecount = new Wt::WText("0"); track2->addWidget(track2details,1,Wt::AlignmentFlag::AlignMiddle | Wt::AlignmentFlag::AlignLeft); track2->addWidget(track2vote,0,Wt::AlignmentFlag::AlignMiddle | Wt::AlignmentFlag::AlignRight); track2->addWidget(track2votecount,0,Wt::AlignmentFlag::AlignMiddle | Wt::AlignmentFlag::AlignLeft); track3 = new Wt::WHBoxLayout(); track3details = new TrackDetails(); track3details->changeBackgroundColor(Wt::WColor("gainsboro")); track3vote = new Wt::WPushButton(); track3vote->setTextFormat(Wt::XHTMLText); track3vote->decorationStyle().font().setFamily(Wt::WFont::Default,"FontAwesome"); track3vote->setMaximumSize(Wt::WLength(50,Wt::WLength::Pixel),Wt::WLength(50,Wt::WLength::Pixel)); track3vote->setText(""); track3votecount = new Wt::WText("0"); track3->addWidget(track3details,1,Wt::AlignmentFlag::AlignMiddle | Wt::AlignmentFlag::AlignLeft); track3->addWidget(track3vote,0,Wt::AlignmentFlag::AlignMiddle | Wt::AlignmentFlag::AlignRight); track3->addWidget(track3votecount,0,Wt::AlignmentFlag::AlignMiddle | Wt::AlignmentFlag::AlignLeft); track1vote->clicked().connect(this, &PlayerInterface::vote1clicked); track2vote->clicked().connect(this, &PlayerInterface::vote2clicked); track3vote->clicked().connect(this, &PlayerInterface::vote3clicked); interfaceLayout->addWidget(playControlWidget); interfaceLayout->addWidget(currentTrackProgress); interfaceLayout->addWidget(mainDisplay); mainDisplay->addTab(voteMetaContainer,"Up Next",Wt::WTabWidget::PreLoading); mainDisplay->addTab(requestPane, "Make Request", Wt::WTabWidget::LazyLoading); playControlWidget->addStyleClass("panel"); playControlWidget->addStyleClass("panel-default"); playControlWidget->decorationStyle().setBackgroundColor(Wt::WColor("gainsboro")); voteMetaLayout->addWidget(voteControlContainer,0,Wt::AlignmentFlag::AlignCenter); playControlLayout->addWidget(playpause,0,Wt::AlignmentFlag::AlignLeft | Wt::AlignmentFlag::AlignMiddle); playControlLayout->addWidget(currentTrackDetails,0,Wt::AlignmentFlag::AlignCenter | Wt::AlignmentFlag::AlignMiddle); playControlLayout->addWidget(skipControls,0,Wt::AlignmentFlag::AlignRight | Wt::AlignmentFlag::AlignMiddle); votePanel->setTitle("Upcoming Tracks To Vote On"); votePanel->decorationStyle().setBackgroundColor(Wt::WColor("lightsteelblue")); voteControlContainer->addWidget(votePanel); votePanel->setCentralWidget(voteTracksContainer); voteTracksContainer->setLayout(voteTracksLayout); voteTracksLayout->addLayout(track1); voteTracksLayout->addSpacing(Wt::WLength(20,Wt::WLength::Pixel)); voteTracksLayout->addLayout(track2); voteTracksLayout->addSpacing(Wt::WLength(20,Wt::WLength::Pixel)); voteTracksLayout->addLayout(track3); } void PlayerInterface::playpauseClicked() { if(!isPaused) { GroovePlayerMgr::getInstance()->lastInternalEvents.push_back(GroovePlayerMgr::PlayerEvent() = {GroovePlayerMgr::PlayerEventType::PLAYING_PAUSED, app->currentUser, std::list{GroovePlayerMgr::getInstance()->currentTrack}}); } else { GroovePlayerMgr::getInstance()->lastInternalEvents.push_back(GroovePlayerMgr::PlayerEvent() = {GroovePlayerMgr::PlayerEventType::PLAYING_RESUMED, app->currentUser, std::list{GroovePlayerMgr::getInstance()->currentTrack}}); } } void PlayerInterface::skipRequestClicked() { if(!isPaused) { GroovePlayerMgr::getInstance()->lastInternalEvents.push_back(GroovePlayerMgr::PlayerEvent() = {GroovePlayerMgr::PlayerEventType::SKIP_REQUESTED, app->currentUser, std::list{GroovePlayerMgr::getInstance()->currentTrack}}); } } void PlayerInterface::skipDenyClicked() { if(!isPaused) { GroovePlayerMgr::getInstance()->lastInternalEvents.push_back(GroovePlayerMgr::PlayerEvent() = {GroovePlayerMgr::PlayerEventType::SKIP_VOTE_CAST_AGAINST, app->currentUser, std::list{GroovePlayerMgr::getInstance()->currentTrack}}); } } void PlayerInterface::vote1clicked() { track1vote->setEnabled(false); track2vote->setEnabled(false); track3vote->setEnabled(false); GroovePlayerMgr::getInstance()->lastInternalEvents.push_back(GroovePlayerMgr::PlayerEvent() = {GroovePlayerMgr::PlayerEventType::VOTE_CAST, app->currentUser, std::list{track1details->extractTrackFromDetails()}}); } void PlayerInterface::vote2clicked() { track1vote->setEnabled(false); track2vote->setEnabled(false); track3vote->setEnabled(false); GroovePlayerMgr::getInstance()->lastInternalEvents.push_back(GroovePlayerMgr::PlayerEvent() = {GroovePlayerMgr::PlayerEventType::VOTE_CAST, app->currentUser, std::list{track2details->extractTrackFromDetails()}}); } void PlayerInterface::vote3clicked() { track1vote->setEnabled(false); track2vote->setEnabled(false); track3vote->setEnabled(false); GroovePlayerMgr::getInstance()->lastInternalEvents.push_back(GroovePlayerMgr::PlayerEvent() = {GroovePlayerMgr::PlayerEventType::VOTE_CAST, app->currentUser, std::list{track3details->extractTrackFromDetails()}}); } void PlayerInterface::updateSkipRequestedFromServer() { skipRequest->setHidden(true); skipDeny->setHidden(false); } void PlayerInterface::updateSkipDeniedFromServer() { skipDeny->setHidden(true); skipRequest->setHidden(false); } void PlayerInterface::updateVotingEnded(AudioTrack winner) { skipRequest->setEnabled(false); track1vote->setEnabled(false); track2vote->setEnabled(false); track3vote->setEnabled(false); //show winning track if(track1details->trackMatches(winner)) track1details->changeBackgroundColor(Wt::WColor("gold")); else if(track2details->trackMatches(winner)) track2details->changeBackgroundColor(Wt::WColor("gold")); else if(track3details->trackMatches(winner)) track3details->changeBackgroundColor(Wt::WColor("gold")); } void PlayerInterface::updateVoteCount(AudioTrack trackVoted) { //update track vote if(track1details->trackMatches(trackVoted)) track1votecount->setText(std::to_string(std::stoi(track1votecount->text())+1)); else if(track2details->trackMatches(trackVoted)) track2votecount->setText(std::to_string(std::stoi(track2votecount->text())+1)); else if(track3details->trackMatches(trackVoted)) track3votecount->setText(std::to_string(std::stoi(track3votecount->text())+1)); } void PlayerInterface::playpauseUpdated() { if(isPaused) { skipRequest->setEnabled(false); playpause->setText(Wt::WString::fromUTF8("")); } else { if(!GroovePlayerMgr::getInstance()->voteEndedButNotNextTrackYet) skipRequest->setEnabled(true); playpause->setText(Wt::WString::fromUTF8("")); } } void PlayerInterface::updateProgressFromTimer() { if(currentTrackProgress->maximum() >= currentTrackProgress->value()+1) { double secondsIn; groove_player_position(GroovePlayerMgr::getInstance()->currentPlayer,nullptr, &secondsIn); currentTrackProgress->setValue(secondsIn); } else if(currentTrackProgress->maximum() < currentTrackProgress->value()+1) { currentTrackProgress->setValue(currentTrackProgress->maximum()); trackProgress->stop(); } } void PlayerInterface::updateDetailsFromServer(AudioTrack track) { //Find current song playing and set progress state. double secondsIn; groove_player_position(GroovePlayerMgr::getInstance()->currentPlayer,nullptr, &secondsIn); currentTrackProgress->setMaximum(track.trackLengthSeconds); currentTrackProgress->setValue(secondsIn); isPaused = groove_playlist_playing(GroovePlayerMgr::getInstance()->currentPlaylist) == 0; if(!isPaused) { trackProgress->start(); } playpauseUpdated(); if(GroovePlayerMgr::getInstance()->currentSkipRequester.size() > 0) { updateSkipRequestedFromServer(); } else { updateSkipDeniedFromServer(); } currentTrackDetails->updateWithTrackDetails(track); } void PlayerInterface::updateVoteableTracksFromServer(std::list tracks) { //Update current vote items auto trackIter = tracks.begin(); track1details->updateWithTrackDetails(*trackIter); track2details->updateWithTrackDetails(*++trackIter); track3details->updateWithTrackDetails(*++trackIter); track1vote->setEnabled(true); track2vote->setEnabled(true); track3vote->setEnabled(true); //reset color state of tracks track1details->changeBackgroundColor(Wt::WColor("gainsboro")); track2details->changeBackgroundColor(Wt::WColor("gainsboro")); track3details->changeBackgroundColor(Wt::WColor("gainsboro")); } void PlayerInterface::updateVoteTrackState() { //Update vote counts of tracks auto trackIter = GroovePlayerMgr::getInstance()->currentVoteStatus.begin(); track1votecount->setText(std::to_string(trackIter->second)); ++trackIter; track2votecount->setText(std::to_string(trackIter->second)); ++trackIter; track3votecount->setText(std::to_string(trackIter->second)); //Make sure vote buttons are disabled if this user already voted for(User user : GroovePlayerMgr::getInstance()->currentUsersVoted) { if(user.username == app->currentUser.username) { track1vote->setEnabled(false); track2vote->setEnabled(false); track3vote->setEnabled(false); } } }