diff --git a/include/app/arbiter.hpp b/include/app/arbiter.hpp index 8ed2b5d3..78202f14 100644 --- a/include/app/arbiter.hpp +++ b/include/app/arbiter.hpp @@ -68,4 +68,5 @@ class Arbiter : public QObject { void cursor_changed(bool enabled); void action_changed(Action *action, QString key); void openauto_full_screen(bool fullscreen); + void openauto_connection_changed(bool connected); }; diff --git a/include/app/quick_views/media.hpp b/include/app/quick_views/media.hpp new file mode 100644 index 00000000..3603545b --- /dev/null +++ b/include/app/quick_views/media.hpp @@ -0,0 +1,78 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "app/quick_views/quick_view.hpp" +#include "AAHandler.hpp" + +class Arbiter; +class MediaWidget; + +class MediaQuickView : public QFrame, public QuickView { + Q_OBJECT + + public: + MediaQuickView(Arbiter &arbiter); + QWidget *centralwidget; + QHBoxLayout *horizontalLayout; + QLabel *album_art_label; + QWidget *widget_2; + QVBoxLayout *verticalLayout_2; + QWidget *widget_3; + QHBoxLayout *horizontalLayout_3; + QSpacerItem *horizontalSpacer_5; + QPushButton *prev_button; + QPushButton *play_button; + QPushButton *next_button; + QSpacerItem *horizontalSpacer_6; + QLabel *track_progress_label; + QLabel *title_label; + QProgressBar *progressBar; + MediaWidget *mediaWidget; + + void init() override; + +}; + +class MediaWidget : public QWidget +{ + Q_OBJECT + +public: + MediaWidget(Arbiter &arbiter, QWidget *parent = 0); + void clear(); + +public slots: + void updateMetadata(const aasdk::proto::messages::MediaInfoChannelMetadataData& metadata); + void updatePlayback(const aasdk::proto::messages::MediaInfoChannelPlaybackData& playback); + +protected: + void paintEvent(QPaintEvent *event) override; + void resizeEvent(QResizeEvent *event) override; + void mousePressEvent(QMouseEvent *event) override; +private: + Arbiter &arbiter; + aasdk::proto::messages::MediaInfoChannelMetadataData metadata_; + aasdk::proto::messages::MediaInfoChannelPlaybackData playback_; + bool connected = false; + QPoint title_pos; + bool scroll_text_left = true; + QTimer *scroll_timer; + QRect play_rect; + QRect prev_rect; + QRect next_rect; +}; + + + + diff --git a/src/app/pages/openauto.cpp b/src/app/pages/openauto.cpp index afdaeae4..8fbe1130 100644 --- a/src/app/pages/openauto.cpp +++ b/src/app/pages/openauto.cpp @@ -24,7 +24,7 @@ OpenAutoWorker::OpenAutoWorker(std::function callback, bool night_mo { this->create_usb_workers(); this->create_io_service_workers(); - + this->app->waitForDevice(true); AAHandler *aa_handler = arbiter.android_auto().handler; service_factory.setAndroidAutoInterface(aa_handler); @@ -427,8 +427,10 @@ void OpenAutoPage::init() std::function callback = [frame = this->frame](bool active) { frame->toggle(active); }; this->worker = new OpenAutoWorker(callback, this->arbiter.theme().mode == Session::Theme::Dark, frame, this->arbiter); - + connect(this->frame, &OpenAutoFrame::toggle, [this](bool enable){ + emit arbiter.openauto_connection_changed(enable); + if (!enable && this->frame->is_fullscreen()) { this->addWidget(frame); this->frame->toggle_fullscreen(); diff --git a/src/app/quick_views/media.cpp b/src/app/quick_views/media.cpp new file mode 100644 index 00000000..9ac486b6 --- /dev/null +++ b/src/app/quick_views/media.cpp @@ -0,0 +1,226 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "app/arbiter.hpp" +#include "app/widgets/dialog.hpp" +#include "app/quick_views/media.hpp" +#include "app/utilities/icon_engine.hpp" + +MediaQuickView::MediaQuickView(Arbiter &arbiter) + : QFrame() + , QuickView(arbiter, "Media", this) +{ + +} + +void MediaQuickView::init(){ + + AAHandler *aa_handler = arbiter.android_auto().handler; + mediaWidget = new MediaWidget(this->arbiter,this); + + horizontalLayout = new QHBoxLayout(this); + horizontalLayout->setObjectName(QString::fromUtf8("horizontalLayout")); + horizontalLayout->setContentsMargins(0, 0, 0, 0); + mediaWidget = new MediaWidget(this->arbiter, this); + horizontalLayout->addWidget(mediaWidget); + + connect(aa_handler, &AAHandler::aa_media_playback_update, [this](const aasdk::proto::messages::MediaInfoChannelPlaybackData& playback){ + mediaWidget->updatePlayback(playback); + }); + + connect(aa_handler, &AAHandler::aa_media_metadata_update, [this](const aasdk::proto::messages::MediaInfoChannelMetadataData& metadata){ + mediaWidget->updateMetadata(metadata); + }); + +} + +MediaWidget::MediaWidget(Arbiter &arbiter, QWidget *parent) + : QWidget(parent) + ,arbiter(arbiter) +{ + + scroll_timer = new QTimer(this); + scroll_timer->start(33);//30fps + connect(scroll_timer, &QTimer::timeout, [this](){ + + if(metadata_.has_track_name() && metadata_.has_artist_name()){ + QString track_info(QString::fromStdString(metadata_.artist_name()) + + " - " + + QString::fromStdString(metadata_.track_name())); + QFont myFont("arial", 10); + QFontMetrics fm(myFont); + int text_width=fm.width(track_info); + + int text_rect_width = (width() / 2) - (height() / 2 + (height() * 2)); + + if(text_width > text_rect_width){ + + if(scroll_text_left){ + title_pos.setX(title_pos.x() - 1); + if((title_pos.x() + text_width) < height() + text_rect_width){ + scroll_text_left = false; + } + + } else{ + title_pos.setX(title_pos.x() + 1); + if(title_pos.x() > height()){ + scroll_text_left = true; + } + } + + } + + } + + this->update(); + + }); + + connect(&arbiter, &Arbiter::openauto_connection_changed, [this](bool connected){ + + this->connected = connected; + + }); + +} + +void MediaWidget::paintEvent(QPaintEvent *event) +{ + + // Setup + QPainter painter(this); + painter.setRenderHint(QPainter::HighQualityAntialiasing); + if(arbiter.theme().mode == Session::Theme::Mode::Dark){ + painter.setBackground(QBrush(QColor(48,48,48))); + painter.setPen(QPen(Qt::white,1)); + } else { + painter.setBackground(QBrush(QColor(250,250,250))); + painter.setPen(QPen(Qt::black,1)); + } + + painter.eraseRect(0,0,width(),height()); + + /*** ALBUM ART ***/ + if(this->metadata_.has_album_art() && connected){ + + QImage art; + art.loadFromData(QByteArray::fromStdString(metadata_.album_art())); + QSize size = QSize(height(), height()); + auto scaled = art.scaled(size, Qt::IgnoreAspectRatio, Qt::FastTransformation); + painter.drawImage(QPoint(0,0),scaled); + + } + + /*** TRACK TITLE ***/ + int text_rect_width = (width() / 2) - (height() / 2 + (height() * 2)); + if(metadata_.has_track_name() && metadata_.has_artist_name() && connected){ + QString track_info(QString::fromStdString(metadata_.artist_name()) + + " - " + + QString::fromStdString(metadata_.track_name())); + QFont myFont("arial", 10); + painter.setFont(myFont); + painter.setClipRect(height(),0, text_rect_width ,height()); + painter.drawText(title_pos, track_info); + painter.setClipping(false); + } + + /*** PREV BUTTON ***/ + QIcon prev_icon(new IconEngine(this->arbiter, QString("://icons/skip_previous.svg"), true)); + QPixmap prev_pixmap = prev_icon.pixmap(QSize(128,128)); + painter.drawPixmap(prev_rect,prev_pixmap); + + /*** PLAY/PAUSE BUTTON ***/ + if(this->playback_.has_track_progress() && connected && + metadata_.has_track_length() && metadata_.track_length() != 0){ + + QPen progressBGPen = QPen(arbiter.theme().color(),4); + painter.setPen(progressBGPen); + painter.drawArc(play_rect,1440,5760); + QPen progressPen = QPen(QColor(70,70,70),4); + painter.setPen(progressPen); + int step = 5760 / metadata_.track_length(); + int invVal = metadata_.track_length() - playback_.track_progress(); + int val = step * invVal; + painter.drawArc(play_rect,1440,val); + + } else { + QPen progressPen = QPen(QColor(70,70,70),4); + painter.setPen(progressPen); + painter.drawArc(play_rect,1440,5760); + } + + if(playback_.has_playback_state() && playback_.playback_state() == aasdk::proto::messages::MediaInfoChannelPlaybackData_PlaybackState_PLAY){ + QIcon icon(new IconEngine(this->arbiter, QString("://icons/pause.svg"), true)); + QPixmap pause = icon.pixmap(QSize(128,128)); + painter.drawPixmap(play_rect,pause); + + } else { + QIcon icon(new IconEngine(this->arbiter, QString("://icons/play.svg"), true)); + QPixmap play = icon.pixmap(QSize(128,128)); + painter.drawPixmap(play_rect,play); + } + + /**** NEXT BUTTON ****/ + QIcon next_icon(new IconEngine(this->arbiter, QString("://icons/skip_next.svg"), true)); + QPixmap next_pixmap = next_icon.pixmap(QSize(128,128)); + painter.drawPixmap(next_rect,next_pixmap); + +} + +void MediaWidget::resizeEvent(QResizeEvent *event) +{ + prev_rect = QRect((width() / 2) - (height() / 2 + height()), 8,height() - 16,height() - 16); + play_rect = QRect((width() / 2) - (height() / 2), 8,height() - 16,height() - 16); + next_rect = QRect((width() / 2) + (height() / 2), 8,height() - 16,height() - 16); + +} + +void MediaWidget::mousePressEvent(QMouseEvent *event) +{ + + if(event->button()==Qt::LeftButton) + { + + AAHandler *aa_handler = arbiter.android_auto().handler; + if(prev_rect.contains(event->pos())){ + aa_handler->injectButtonPress(aasdk::proto::enums::ButtonCode::PREV,openauto::projection::ButtonEventType::RELEASE); + } + if(play_rect.contains(event->pos())){ + aa_handler->injectButtonPress(aasdk::proto::enums::ButtonCode::TOGGLE_PLAY,openauto::projection::ButtonEventType::PRESS); + aa_handler->injectButtonPress(aasdk::proto::enums::ButtonCode::TOGGLE_PLAY,openauto::projection::ButtonEventType::RELEASE); + } + if(next_rect.contains(event->pos())){ + aa_handler->injectButtonPress(aasdk::proto::enums::ButtonCode::NEXT,openauto::projection::ButtonEventType::RELEASE); + } + + } +} + +void MediaWidget::updatePlayback(const aasdk::proto::messages::MediaInfoChannelPlaybackData& playback) +{ + + this->playback_ = playback; + this->update(); + +} + +void MediaWidget::updateMetadata(const aasdk::proto::messages::MediaInfoChannelMetadataData& metadata) +{ + + title_pos = QPoint(height() + 8, (height() / 2) + 5);//reset + this->metadata_ = metadata; + this->update(); + +} + + diff --git a/src/app/session.cpp b/src/app/session.cpp index 637567e3..578f8a61 100644 --- a/src/app/session.cpp +++ b/src/app/session.cpp @@ -23,6 +23,7 @@ #include "aasdk_proto/ButtonCodeEnum.pb.h" #include "app/session.hpp" +#include "app/quick_views/media.hpp" QDir Session::plugin_dir(QString plugin) { @@ -89,7 +90,8 @@ Session::Layout::ControlBar::ControlBar(QSettings &settings, Arbiter &arbiter) new NullQuickView(arbiter), new VolumeQuickView(arbiter), new BrightnessQuickView(arbiter), - new ComboQuickView(arbiter) + new ComboQuickView(arbiter), + new MediaQuickView(arbiter) }; this->curr_quick_view = this->quick_views_.value(settings.value("Layout/ControlBar/quick_view", 0).toInt()); diff --git a/src/app/window.cpp b/src/app/window.cpp index e1d7b2ed..c673685d 100644 --- a/src/app/window.cpp +++ b/src/app/window.cpp @@ -107,8 +107,6 @@ QWidget *Dash::control_bar() const quick_views->setCurrentWidget(quick_view->widget()); }); - layout->addStretch(); - auto dialog = new Dialog(this->arbiter, true, this->arbiter.window()); dialog->set_title("Power Off"); dialog->set_body(this->power_control());