#include "detailview.h" #include "../../quick/embyimageprovider.h" #include "../../quick/quickpagehost.h" #include "../../utils/mediaitemutils.h" #include "../../utils/playerpreferenceutils.h" #include "detailviewmodel.h" #include #include #include #include #include #include #include #include #include #include #include #include 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 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 DetailView::playSelected(MediaItem item, int sourceIndex, bool resume) { if (!m_core || !m_core->mediaService() || item.id.isEmpty()) co_return; QPointer 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(ConfigKeys::PlayerAudioLang, "auto"), ConfigStore::instance()->get(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")); } }