Files
qemby/src/qEmbyApp/views/media/detailview.cpp
T

161 lines
5.8 KiB
C++

#include "detailview.h"
#include "../../quick/embyimageprovider.h"
#include "../../quick/quickpagehost.h"
#include "../../utils/mediaitemutils.h"
#include "../../utils/playerpreferenceutils.h"
#include "detailviewmodel.h"
#include <config/config_keys.h>
#include <config/configstore.h>
#include <models/media/playerlaunchcontext.h>
#include <qembycore.h>
#include <services/media/mediaservice.h>
#include <QCursor>
#include <QMetaObject>
#include <QPointer>
#include <QQuickItem>
#include <QQuickWidget>
#include <QVBoxLayout>
#include <qcorotask.h>
DetailView::DetailView(QEmbyCore *core, QWidget *parent)
: BaseView(core, parent) {
setObjectName(QStringLiteral("detail-view"));
setAttribute(Qt::WA_StyledBackground, true);
auto *layout = new QVBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing(0);
m_quickHost = new QuickPageHost(this);
m_viewModel = new DetailViewModel(core, m_quickHost);
m_quickHost->setContextProperty(QStringLiteral("detailPage"), m_viewModel);
m_quickHost->addImageProvider(QStringLiteral("emby"),
new EmbyImageProvider(core));
m_quickHost->addImageProvider(QStringLiteral("adaptiveicon"),
new AdaptiveIconProvider());
m_quickHost->load(
QUrl(QStringLiteral("qrc:/qt/qml/qEmby/qml/DetailPage.qml")));
layout->addWidget(m_quickHost);
connect(m_quickHost, &QuickPageHost::pageShown, m_viewModel,
[this]() { m_viewModel->setActive(true); });
connect(m_quickHost, &QuickPageHost::pageHidden, m_viewModel,
[this]() { m_viewModel->setActive(false); });
connect(m_viewModel, &DetailViewModel::itemActivated, this,
[this](const MediaItem &item) {
if (item.type == QLatin1String("Season")) {
const QString seriesId = item.seriesId.isEmpty()
? m_viewModel->item().id
: item.seriesId;
emit navigateToSeason(seriesId, item.id, item.name);
} else if (item.type == QLatin1String("BoxSet") ||
item.type == QLatin1String("Playlist") ||
item.type == QLatin1String("Folder")) {
emit navigateToFolder(item.id, item.name);
} else if (item.type == QLatin1String("Person")) {
emit navigateToPerson(item.id, item.name);
} else {
emit navigateToDetail(item.id, item.name, item);
}
});
connect(m_viewModel, &DetailViewModel::genreActivated, this,
[this](const QString &genre) {
emit navigateToFilteredView(QStringLiteral("Genre"), genre);
});
connect(m_viewModel, &DetailViewModel::playRequested, this,
[this](const MediaItem &item, int sourceIndex, bool resume) {
playSelected(item, sourceIndex, resume);
});
connect(m_viewModel, &DetailViewModel::favoriteRequested, this,
&BaseView::handleFavoriteRequested);
connect(m_viewModel, &DetailViewModel::playedRequested, this,
[this](const MediaItem &item, bool played) {
if (played)
handleMarkPlayedRequested(item);
else
handleMarkUnplayedRequested(item);
});
connect(m_viewModel, &DetailViewModel::moreRequested, this,
[this](const MediaItem &item) {
handleMoreMenuRequested(item, QCursor::pos());
});
}
QCoro::Task<void> DetailView::loadItem(const QString &itemId,
const MediaItem &seedItem) {
co_await m_viewModel->loadItem(itemId, seedItem);
}
void DetailView::prepareForStackLeave() { m_viewModel->setActive(false); }
void DetailView::scrollToTop() {
if (QQuickItem *root = m_quickHost->quickWidget()->rootObject())
QMetaObject::invokeMethod(root, "scrollToTop");
}
void DetailView::onMediaItemUpdated(const MediaItem &item) {
m_viewModel->updateItem(item);
}
void DetailView::beginOptimisticPlayedUpdate() {
m_viewModel->setActionBusy(true);
}
void DetailView::endOptimisticPlayedUpdate() {
m_viewModel->setActionBusy(false);
}
QCoro::Task<void> DetailView::playSelected(MediaItem item, int sourceIndex,
bool resume) {
if (!m_core || !m_core->mediaService() || item.id.isEmpty())
co_return;
QPointer<DetailView> guard(this);
try {
if (item.mediaSources.isEmpty()) {
const PlaybackInfo info =
co_await m_core->mediaService()->getPlaybackInfo(item.id);
if (!guard)
co_return;
item.mediaSources = info.mediaSources;
}
QVariant launchData;
QString sourceId = item.id;
QString streamUrl;
if (!item.mediaSources.isEmpty()) {
sourceIndex = qBound(0, sourceIndex, item.mediaSources.size() - 1);
MediaSourceInfo selected = item.mediaSources.at(sourceIndex);
PlayerPreferenceUtils::applyPreferredStreamRules(
selected,
ConfigStore::instance()->get<QString>(ConfigKeys::PlayerAudioLang,
"auto"),
ConfigStore::instance()->get<QString>(ConfigKeys::PlayerSubLang,
"auto"));
sourceId = selected.id;
PlayerLaunchContext context;
context.mediaItem = item;
context.selectedSource = selected;
launchData = QVariant::fromValue(context);
streamUrl = m_core->mediaService()->getStreamUrl(item.id, selected);
} else {
streamUrl = m_core->mediaService()->getStreamUrl(item.id, sourceId);
}
if (!guard)
co_return;
const long long startTicks =
resume ? item.userData.playbackPositionTicks : 0;
emit navigateToPlayer(item.id, MediaItemUtils::playbackTitle(item),
streamUrl, startTicks, launchData);
} catch (...) {
if (guard)
m_viewModel->setTransientError(tr("Unable to prepare playback"));
}
}