feat: route library browsing through QML shell

This commit is contained in:
dela
2026-07-15 14:03:31 +08:00
parent a411fd396a
commit e2357aaa32
13 changed files with 439 additions and 117 deletions
+19 -2
View File
@@ -9,7 +9,8 @@ Item {
property var navigationController: navigation
// Keep this allow-list deliberately small until each page's context
// ViewModel has been moved to the root Quick host.
property var enabledRoutes: ["home", "favorites", "search"]
property var enabledRoutes: ["home", "favorites", "search", "category",
"library", "person", "filtered"]
property var currentRoute: navigationController
? navigationController.currentRoute
: ({ "name": "navigationError",
@@ -69,7 +70,9 @@ Item {
}
function routeImplemented(name) {
return name === "home" || name === "favorites" || name === "search";
return name === "home" || name === "favorites" || name === "search"
|| name === "category" || name === "library" || name === "person"
|| name === "filtered";
}
function routeKnown(name) {
@@ -103,6 +106,11 @@ Item {
case "home": return homeComponent;
case "favorites": return favoritesComponent;
case "search": return searchComponent;
case "category": return categoryComponent;
case "library":
case "person":
case "filtered":
return libraryComponent;
default:
return null;
}
@@ -185,6 +193,13 @@ Item {
return true;
}
function scrollToTop() {
if (!pageLoader.item)
return false;
callHook(pageLoader.item, "scrollToTop", undefined);
return true;
}
onCurrentRouteChanged: applyRoute(currentRoute)
onActiveChanged: {
if (!pageLoader.item)
@@ -221,6 +236,8 @@ Item {
Component { id: homeComponent; DashboardPage { anchors.fill: parent } }
Component { id: favoritesComponent; FavoritesPage { anchors.fill: parent } }
Component { id: searchComponent; SearchPage { anchors.fill: parent } }
Component { id: categoryComponent; CategoryPage { anchors.fill: parent } }
Component { id: libraryComponent; LibraryPage { anchors.fill: parent } }
Component {
id: recoveryComponent
@@ -191,6 +191,9 @@ bool NavigationController::normalize(const QVariantMap &request,
QStringList identity;
for (const QString &field : required)
identity << encoded(params.value(field).toString());
if (name == QLatin1String("category") &&
params.value(QStringLiteral("favorite")).toBool())
identity << QStringLiteral("favorite");
route->key = identity.isEmpty() ? name : name + QLatin1Char(':') + identity.join(QLatin1Char(':'));
return true;
}
@@ -34,6 +34,14 @@ int main(int argc, char **argv)
"search query participates in the route key");
ok &= check(navigation.back() && navigation.currentRoute().value("name") == "home",
"back returns from search to its session root");
ok &= check(navigation.push({{"name", "category"},
{"params", QVariantMap{{"categoryId", "Movie"},
{"favorite", true}}}}),
"accepts a favorite category route");
ok &= check(navigation.currentRoute().value("key") ==
"category:Movie:favorite",
"favorite category has a distinct route identity");
ok &= check(navigation.back(), "returns from favorite category");
ok &= check(navigation.push({{"name", "library"},
{"params", QVariantMap{{"libraryId", "lib/1"},
{"title", "Movies"}}}}),
+147 -93
View File
@@ -214,119 +214,111 @@ void LibraryViewModel::setActive(bool active) {
m_active = active;
if (!active) {
++m_generation;
if (m_loading || m_loadingMore)
if (m_routeRequestInFlight || m_loading || m_loadingMore)
m_reloadOnActivate = true;
m_routeRequestInFlight = false;
m_loading = false;
m_loadingMore = false;
emit stateChanged();
} else if (m_reloadOnActivate) {
m_reloadOnActivate = false;
launchReload();
launchCurrentRouteLoad();
}
}
QCoro::Task<void> LibraryViewModel::loadLibrary(QString libraryId,
QString libraryName) {
libraryId = libraryId.trimmed();
if (isCurrentRoute(LibraryMode, libraryId, {})) {
if (m_title != libraryName) {
m_title = std::move(libraryName);
emit stateChanged();
}
co_return;
}
const quint64 generation = ++m_generation;
m_mode = LibraryMode;
m_targetId = std::move(libraryId);
m_title = std::move(libraryName);
m_filterType.clear();
m_filterValue.clear();
configureRoute(LibraryMode, std::move(libraryId), std::move(libraryName));
if (!m_active) {
m_reloadOnActivate = true;
co_return;
}
co_await loadCurrentRoute(generation);
}
QCoro::Task<void> LibraryViewModel::loadPerson(QString personId,
QString personName) {
personId = personId.trimmed();
if (isCurrentRoute(PersonMode, personId, {})) {
if (m_title != personName) {
m_title = std::move(personName);
emit stateChanged();
}
co_return;
}
const quint64 generation = ++m_generation;
configureRoute(PersonMode, std::move(personId), std::move(personName));
if (!m_active) {
m_reloadOnActivate = true;
co_return;
}
co_await loadCurrentRoute(generation);
}
QCoro::Task<void> LibraryViewModel::loadFiltered(QString filterType,
QString filterValue) {
filterType = filterType.trimmed();
filterValue = filterValue.trimmed();
if (isCurrentRoute(FilteredMode, filterType, filterValue))
co_return;
const quint64 generation = ++m_generation;
configureRoute(FilteredMode, std::move(filterType), std::move(filterValue));
if (!m_active) {
m_reloadOnActivate = true;
co_return;
}
co_await loadCurrentRoute(generation);
}
bool LibraryViewModel::isCurrentRoute(Mode mode, const QString &primary,
const QString &secondary) const {
if (!m_routeInitialized || m_mode != mode)
return false;
if (mode == FilteredMode)
return m_filterType == primary && m_filterValue == secondary;
return m_targetId == primary;
}
void LibraryViewModel::configureRoute(Mode mode, QString primary,
QString secondary) {
m_routeInitialized = true;
m_mode = mode;
m_currentItem = {};
m_tabIndex = 0;
m_firstTabText = tr("All");
m_tabsVisible = false;
m_favoriteVisible = false;
m_reloadOnActivate = false;
if (mode == FilteredMode) {
m_targetId.clear();
m_filterType = std::move(primary);
m_filterValue = std::move(secondary);
m_title = m_filterValue;
} else {
m_targetId = std::move(primary);
m_title = std::move(secondary);
m_filterType.clear();
m_filterValue.clear();
}
restorePreferences();
emit stateChanged();
emit controlsChanged();
if (!m_active) {
m_reloadOnActivate = true;
co_return;
}
QPointer<LibraryViewModel> guard(this);
if (m_active && m_core && m_core->mediaService() && !m_targetId.isEmpty()) {
try {
const MediaItem item =
co_await m_core->mediaService()->getItemDetail(m_targetId);
if (!guard || !m_active || generation != m_generation)
co_return;
if (item.id == m_targetId)
configureCurrentItem(item);
} catch (const std::exception &error) {
if (!guard || generation != m_generation)
co_return;
qWarning() << "[LibraryViewModel] detail probe failed:" << error.what();
}
}
if (!guard || !m_active || generation != m_generation)
co_return;
co_await reload();
}
QCoro::Task<void> LibraryViewModel::loadPerson(QString personId,
QString personName) {
const quint64 generation = ++m_generation;
m_mode = PersonMode;
m_targetId = std::move(personId);
m_title = std::move(personName);
m_filterType.clear();
m_filterValue.clear();
m_currentItem = {};
m_tabIndex = 0;
m_tabsVisible = false;
m_favoriteVisible = false;
restorePreferences();
emit stateChanged();
emit controlsChanged();
if (!m_active) {
m_reloadOnActivate = true;
co_return;
}
QPointer<LibraryViewModel> guard(this);
if (m_active && m_core && m_core->mediaService() && !m_targetId.isEmpty()) {
try {
const MediaItem item =
co_await m_core->mediaService()->getItemDetail(m_targetId);
if (!guard || !m_active || generation != m_generation)
co_return;
if (item.id == m_targetId) {
m_currentItem = item;
m_favoriteVisible = true;
emit controlsChanged();
}
} catch (const std::exception &error) {
if (!guard || generation != m_generation)
co_return;
qWarning() << "[LibraryViewModel] person detail failed:" << error.what();
}
}
if (!guard || !m_active || generation != m_generation)
co_return;
co_await reload();
}
QCoro::Task<void> LibraryViewModel::loadFiltered(QString filterType,
QString filterValue) {
++m_generation;
m_mode = FilteredMode;
m_filterType = std::move(filterType);
m_filterValue = std::move(filterValue);
m_targetId.clear();
m_title = m_filterValue;
m_currentItem = {};
m_tabIndex = 0;
m_tabsVisible = false;
m_favoriteVisible = false;
restorePreferences();
emit stateChanged();
emit controlsChanged();
co_await reload();
}
void LibraryViewModel::configureCurrentItem(const MediaItem &item) {
@@ -499,11 +491,72 @@ void LibraryViewModel::updateStats() {
emit stateChanged();
}
void LibraryViewModel::launchCurrentRouteLoad() {
if (!m_active || !m_routeInitialized) {
m_reloadOnActivate = m_routeInitialized;
return;
}
const quint64 generation = ++m_generation;
QCoro::connect(loadCurrentRoute(generation), this, []() {});
}
QCoro::Task<void> LibraryViewModel::loadCurrentRoute(quint64 generation) {
if (!m_active || !m_routeInitialized || generation != m_generation) {
if (!m_active)
m_reloadOnActivate = true;
co_return;
}
m_routeRequestInFlight = true;
m_loading = true;
m_loadingMore = false;
m_hasMore = false;
m_totalCount = 0;
m_errorText.clear();
m_statsText = tr("Loading...");
m_items.clear();
emit stateChanged();
QPointer<LibraryViewModel> guard(this);
if (m_mode != FilteredMode && m_core && m_core->mediaService() &&
!m_targetId.isEmpty()) {
try {
const MediaItem item =
co_await m_core->mediaService()->getItemDetail(m_targetId);
if (!guard || !m_active || generation != m_generation)
co_return;
if (item.id == m_targetId) {
if (m_mode == PersonMode) {
m_currentItem = item;
m_favoriteVisible = true;
emit controlsChanged();
} else {
configureCurrentItem(item);
}
}
} catch (const std::exception &error) {
if (!guard || !m_active || generation != m_generation)
co_return;
qWarning() << (m_mode == PersonMode
? "[LibraryViewModel] person detail failed:"
: "[LibraryViewModel] detail probe failed:")
<< error.what();
}
}
if (!guard || !m_active || generation != m_generation)
co_return;
m_routeRequestInFlight = false;
co_await reload();
}
void LibraryViewModel::launchReload() {
if (!m_active) {
m_reloadOnActivate = true;
return;
}
m_routeRequestInFlight = false;
QCoro::connect(reload(), this, []() {});
}
@@ -512,6 +565,7 @@ QCoro::Task<void> LibraryViewModel::reload() {
m_reloadOnActivate = true;
co_return;
}
m_routeRequestInFlight = false;
const QueryState query = buildQuery();
const quint64 generation = ++m_generation;
m_query = query;
@@ -138,6 +138,9 @@ private:
};
QString preferenceTargetId() const;
bool isCurrentRoute(Mode mode, const QString &primary,
const QString &secondary) const;
void configureRoute(Mode mode, QString primary, QString secondary);
QString sortBy() const;
QueryState buildQuery() const;
bool queryValid(const QueryState &query) const;
@@ -146,6 +149,8 @@ private:
void saveSortPreference();
void saveViewPreference();
void updateStats();
void launchCurrentRouteLoad();
QCoro::Task<void> loadCurrentRoute(quint64 generation);
void launchReload();
QCoro::Task<void> reload();
QCoro::Task<void> fetchNextPage(quint64 generation, QueryState query,
@@ -172,6 +177,8 @@ private:
bool m_tabsVisible = false;
bool m_favoriteVisible = false;
bool m_active = true;
bool m_routeInitialized = false;
bool m_routeRequestInFlight = false;
bool m_reloadOnActivate = false;
int m_tabIndex = 0;
int m_sortIndex = 0;
+26 -1
View File
@@ -237,13 +237,24 @@ void CategoryViewModel::setActive(bool active) {
m_loadingMore = false;
emit stateChanged();
} else if (m_reloadOnActivate) {
const bool clearRecommendCache = m_clearRecommendCacheOnActivate;
m_reloadOnActivate = false;
launchReload();
m_clearRecommendCacheOnActivate = false;
launchReload(clearRecommendCache);
}
}
QCoro::Task<void> CategoryViewModel::loadCategory(QString categoryType,
QString title) {
const bool routeChanged =
m_category != categoryType || m_title != title;
if (!routeChanged) {
if (!m_active)
m_reloadOnActivate = true;
co_return;
}
++m_generation;
m_category = std::move(categoryType);
m_title = std::move(title);
configureCategory();
@@ -251,6 +262,15 @@ QCoro::Task<void> CategoryViewModel::loadCategory(QString categoryType,
emit stateChanged();
emit sortChanged();
emit viewChanged();
if (!m_active) {
m_loading = false;
m_loadingMore = false;
m_reloadOnActivate = true;
m_clearRecommendCacheOnActivate = false;
co_return;
}
co_await reload();
}
@@ -346,6 +366,8 @@ QString CategoryViewModel::sortBy() const {
void CategoryViewModel::launchReload(bool clearRecommendCache) {
if (!m_active) {
m_reloadOnActivate = true;
m_clearRecommendCacheOnActivate =
m_clearRecommendCacheOnActivate || clearRecommendCache;
return;
}
QCoro::connect(reload(clearRecommendCache), this, []() {});
@@ -354,6 +376,8 @@ void CategoryViewModel::launchReload(bool clearRecommendCache) {
QCoro::Task<void> CategoryViewModel::reload(bool clearRecommendCache) {
if (!m_active) {
m_reloadOnActivate = true;
m_clearRecommendCacheOnActivate =
m_clearRecommendCacheOnActivate || clearRecommendCache;
co_return;
}
if (!m_core || !m_core->mediaService() || m_category.isEmpty())
@@ -361,6 +385,7 @@ QCoro::Task<void> CategoryViewModel::reload(bool clearRecommendCache) {
const quint64 generation = ++m_generation;
m_reloadOnActivate = false;
m_clearRecommendCacheOnActivate = false;
m_loading = true;
m_loadingMore = false;
m_errorText.clear();
@@ -138,6 +138,7 @@ private:
bool m_descending = true;
bool m_active = true;
bool m_reloadOnActivate = false;
bool m_clearRecommendCacheOnActivate = false;
int m_sortIndex = 0;
quint64 m_generation = 0;
};
+132 -2
View File
@@ -2,6 +2,7 @@
#include "dashboardviewmodel.h"
#include "favoritesviewmodel.h"
#include "categoryviewmodel.h"
#include "../../components/libraryactionmenu.h"
#include "../../components/mediaimageeditdialog.h"
@@ -9,6 +10,7 @@
#include "../../quick/navigationcontroller.h"
#include "../../quick/quickrouterhost.h"
#include "../search/searchviewmodel.h"
#include "../media/libraryviewmodel.h"
#include <qembycore.h>
#include <services/admin/adminservice.h>
@@ -18,6 +20,8 @@
#include <QCursor>
#include <QDebug>
#include <QPointer>
#include <QQuickItem>
#include <QQuickWidget>
#include <QTimer>
#include <QVBoxLayout>
@@ -39,6 +43,8 @@ HomeQuickRouterView::HomeQuickRouterView(QEmbyCore *core,
m_dashboardViewModel = new UserDashboardViewModel(core, this);
m_favoritesViewModel = new FavoritesViewModel(core, this);
m_searchViewModel = new SearchViewModel(core, this);
m_categoryViewModel = new CategoryViewModel(core, this);
m_libraryViewModel = new LibraryViewModel(core, this);
m_host->setContextProperty(QStringLiteral("dashboardPage"),
m_dashboardViewModel);
@@ -46,6 +52,10 @@ HomeQuickRouterView::HomeQuickRouterView(QEmbyCore *core,
m_favoritesViewModel);
m_host->setContextProperty(QStringLiteral("searchPage"),
m_searchViewModel);
m_host->setContextProperty(QStringLiteral("categoryPage"),
m_categoryViewModel);
m_host->setContextProperty(QStringLiteral("libraryPage"),
m_libraryViewModel);
m_host->loadRouter();
layout->addWidget(m_host);
@@ -112,6 +122,32 @@ HomeQuickRouterView::HomeQuickRouterView(QEmbyCore *core,
{
handleMoreMenuRequested(item, m_host->mapToGlobal(localPos));
});
connect(m_categoryViewModel, &CategoryViewModel::itemActivated,
this, &HomeQuickRouterView::forwardItemActivation);
connect(m_categoryViewModel, &CategoryViewModel::playRequested,
this, &BaseView::handlePlayRequested);
connect(m_categoryViewModel, &CategoryViewModel::favoriteRequested,
this, &BaseView::handleFavoriteRequested);
connect(m_categoryViewModel, &CategoryViewModel::moreRequested,
this, [this](const MediaItem &item)
{
handleMoreMenuRequested(item, QCursor::pos());
});
connect(m_libraryViewModel, &LibraryViewModel::itemActivated,
this, &HomeQuickRouterView::forwardItemActivation);
connect(m_libraryViewModel, &LibraryViewModel::playRequested,
this, &BaseView::handlePlayRequested);
connect(m_libraryViewModel, &LibraryViewModel::favoriteRequested,
this, &BaseView::handleFavoriteRequested);
connect(m_libraryViewModel, &LibraryViewModel::currentFavoriteRequested,
this, &BaseView::handleFavoriteRequested);
connect(m_libraryViewModel, &LibraryViewModel::moreRequested,
this, [this](const MediaItem &item)
{
handleMoreMenuRequested(item, QCursor::pos());
});
}
void HomeQuickRouterView::refreshHome()
@@ -135,6 +171,9 @@ void HomeQuickRouterView::scrollToTop()
m_dashboardViewModel->scrollToTop();
else if (routeName == QLatin1String("favorites"))
m_favoritesViewModel->scrollToTop();
else if (m_host && m_host->quickWidget()->rootObject())
QMetaObject::invokeMethod(m_host->quickWidget()->rootObject(),
"scrollToTop");
}
void HomeQuickRouterView::onMediaItemUpdated(const MediaItem &item)
@@ -142,12 +181,16 @@ void HomeQuickRouterView::onMediaItemUpdated(const MediaItem &item)
m_dashboardViewModel->updateItem(item);
m_favoritesViewModel->updateItem(item);
m_searchViewModel->updateItem(item);
m_categoryViewModel->updateItem(item);
m_libraryViewModel->updateItem(item);
}
void HomeQuickRouterView::onMediaItemRemoved(const QString &itemId)
{
m_dashboardViewModel->removeItem(itemId);
m_favoritesViewModel->removeItem(itemId);
m_categoryViewModel->removeItem(itemId);
m_libraryViewModel->removeItem(itemId);
}
CardContextMenuRequest HomeQuickRouterView::showCardContextMenu(
@@ -227,8 +270,16 @@ void HomeQuickRouterView::updateRouteActivity()
m_favoritesViewModel->setActive(hostActive &&
routeName == QLatin1String("favorites"));
const bool searchActive = hostActive &&
routeName == QLatin1String("search");
updateSearchRoute(route, hostActive);
updateCategoryRoute(route, hostActive);
updateLibraryRoute(route, hostActive);
}
void HomeQuickRouterView::updateSearchRoute(const QVariantMap &route,
bool hostActive)
{
const QString routeName = route.value(QStringLiteral("name")).toString();
const bool searchActive = hostActive && routeName == QLatin1String("search");
if (!searchActive)
{
m_searchViewModel->setActive(false);
@@ -255,11 +306,90 @@ void HomeQuickRouterView::updateRouteActivity()
m_searchViewModel->setActive(true);
}
void HomeQuickRouterView::updateCategoryRoute(const QVariantMap &route,
bool hostActive)
{
const QString routeName = route.value(QStringLiteral("name")).toString();
const bool categoryActive = hostActive &&
routeName == QLatin1String("category");
if (!categoryActive)
{
m_categoryViewModel->setActive(false);
return;
}
const QVariantMap params = route.value(QStringLiteral("params")).toMap();
QString categoryId = params.value(QStringLiteral("categoryId"))
.toString().trimmed();
if (params.value(QStringLiteral("favorite")).toBool())
categoryId.prepend(QStringLiteral("Favorite_"));
const QString title = params.value(QStringLiteral("title")).toString();
const QString routeKey = route.value(QStringLiteral("key")).toString();
const QString routeIdentity = routeKey + QLatin1Char('\n') + title;
if (!categoryId.isEmpty() && routeIdentity != m_categoryRouteKey)
{
m_categoryViewModel->setActive(false);
m_categoryRouteKey = routeIdentity;
QCoro::connect(m_categoryViewModel->loadCategory(categoryId, title),
this, []() {});
}
m_categoryViewModel->setActive(true);
}
void HomeQuickRouterView::updateLibraryRoute(const QVariantMap &route,
bool hostActive)
{
const QString routeName = route.value(QStringLiteral("name")).toString();
const bool libraryActive = hostActive &&
(routeName == QLatin1String("library") ||
routeName == QLatin1String("person") ||
routeName == QLatin1String("filtered"));
if (!libraryActive)
{
m_libraryViewModel->setActive(false);
return;
}
const QVariantMap params = route.value(QStringLiteral("params")).toMap();
const QString routeKey = route.value(QStringLiteral("key")).toString();
const QString title = params.value(QStringLiteral("title")).toString();
const QString routeIdentity = routeKey + QLatin1Char('\n') + title;
if (routeIdentity != m_libraryRouteKey)
{
m_libraryViewModel->setActive(false);
m_libraryRouteKey = routeIdentity;
if (routeName == QLatin1String("library"))
{
QCoro::connect(m_libraryViewModel->loadLibrary(
params.value(QStringLiteral("libraryId")).toString(),
title),
this, []() {});
}
else if (routeName == QLatin1String("person"))
{
QCoro::connect(m_libraryViewModel->loadPerson(
params.value(QStringLiteral("personId")).toString(),
title),
this, []() {});
}
else
{
QCoro::connect(m_libraryViewModel->loadFiltered(
params.value(QStringLiteral("filterType")).toString(),
params.value(QStringLiteral("filterValue")).toString()),
this, []() {});
}
}
m_libraryViewModel->setActive(true);
}
void HomeQuickRouterView::deactivateRoutes()
{
m_dashboardViewModel->setActive(false);
m_favoritesViewModel->setActive(false);
m_searchViewModel->setActive(false);
m_categoryViewModel->setActive(false);
m_libraryViewModel->setActive(false);
}
void HomeQuickRouterView::forwardItemActivation(const MediaItem &item)
@@ -3,6 +3,8 @@
#include "../baseview.h"
class FavoritesViewModel;
class CategoryViewModel;
class LibraryViewModel;
class NavigationController;
class QuickRouterHost;
class SearchViewModel;
@@ -40,6 +42,9 @@ protected:
private:
void updateRouteActivity();
void updateSearchRoute(const QVariantMap &route, bool hostActive);
void updateCategoryRoute(const QVariantMap &route, bool hostActive);
void updateLibraryRoute(const QVariantMap &route, bool hostActive);
void deactivateRoutes();
void forwardItemActivation(const MediaItem &item);
void launchDashboardTask(QCoro::Task<void> &&task);
@@ -54,6 +59,10 @@ private:
UserDashboardViewModel *m_dashboardViewModel = nullptr;
FavoritesViewModel *m_favoritesViewModel = nullptr;
SearchViewModel *m_searchViewModel = nullptr;
CategoryViewModel *m_categoryViewModel = nullptr;
LibraryViewModel *m_libraryViewModel = nullptr;
QString m_searchRouteKey;
QString m_searchQuery;
QString m_categoryRouteKey;
QString m_libraryRouteKey;
};
+70 -17
View File
@@ -259,9 +259,9 @@ void HomeView::setupUi()
auto navigateToDetailSlot = [this](const QString &itemId, const QString &itemName, const MediaItem &seedItem)
{ pushView(createDetailView(itemId, itemName, seedItem)); };
auto navigateToFolderSlot = [this](const QString &id, const QString &name)
{ pushView(createLibraryView(id, name)); };
{ openLibraryRoute(id, name); };
auto navigateToPersonSlot = [this](const QString &id, const QString &name)
{ pushView(createPersonView(id, name)); };
{ openPersonRoute(id, name); };
auto navigateToPlayerSlot = [this](const QString &id, const QString &title, const QString &url, long long ticks,
const QVariant &extraData) { launchPlayer(id, title, url, ticks, extraData); };
auto navigateToSeasonSlot = [this](const QString &seriesId, const QString &seasonId, const QString &seasonName)
@@ -278,12 +278,12 @@ void HomeView::setupUi()
break;
}
}
pushView(createLibraryView(id, name));
openLibraryRoute(id, name);
};
const auto openCategory = [this](const QString &categoryId, const QString &title)
{
m_libraryList->clearSelection();
pushView(createCategoryView(categoryId, title));
openCategoryRoute(categoryId, title);
};
m_useQuickHomeRouter = qEnvironmentVariableIntValue("QEMBY_USE_LEGACY_HOME_PAGES") != 1;
@@ -410,11 +410,11 @@ QWidget *HomeView::createDetailView(const QString &itemId, const QString &itemNa
connect(view, &DetailView::navigateToDetail, this,
[this](const QString &id, const QString &name, const MediaItem &seed) { pushView(createDetailView(id, name, seed)); });
connect(view, &DetailView::navigateToFolder, this,
[this](const QString &id, const QString &name) { pushView(createLibraryView(id, name)); });
[this](const QString &id, const QString &name) { openLibraryRoute(id, name); });
connect(view, &BaseView::navigateToPerson, this,
[this](const QString &id, const QString &name)
{
pushView(createPersonView(id, name));
openPersonRoute(id, name);
});
connect(view, &BaseView::navigateToPlayer, this,
@@ -429,7 +429,7 @@ QWidget *HomeView::createDetailView(const QString &itemId, const QString &itemNa
connect(view, &DetailView::triggerSearch, this, &HomeView::triggerSearch);
connect(view, &BaseView::navigateToFilteredView, this,
[this](const QString &type, const QString &value)
{ pushView(createFilteredView(type, value)); });
{ openFilteredRoute(type, value); });
return view;
}
@@ -449,10 +449,10 @@ QWidget *HomeView::createCategoryView(const QString &categoryId, const QString &
[this](const QString &id, const QString &name, const MediaItem &seed) { pushView(createDetailView(id, name, seed)); });
connect(view, &CategoryView::navigateToFolder, this,
[this](const QString &id, const QString &name) { pushView(createLibraryView(id, name)); });
[this](const QString &id, const QString &name) { openLibraryRoute(id, name); });
connect(view, &CategoryView::navigateToPerson, this,
[this](const QString &id, const QString &name) { pushView(createPersonView(id, name)); });
[this](const QString &id, const QString &name) { openPersonRoute(id, name); });
connect(view, &BaseView::navigateToPlayer, this,
@@ -481,10 +481,10 @@ QWidget *HomeView::createLibraryView(const QString &libraryId, const QString &ti
[this](const QString &id, const QString &name, const MediaItem &seed) { pushView(createDetailView(id, name, seed)); });
connect(view, &LibraryView::navigateToFolder, this,
[this](const QString &id, const QString &name) { pushView(createLibraryView(id, name)); });
[this](const QString &id, const QString &name) { openLibraryRoute(id, name); });
connect(view, &BaseView::navigateToPerson, this,
[this](const QString &id, const QString &name) { pushView(createPersonView(id, name)); });
[this](const QString &id, const QString &name) { openPersonRoute(id, name); });
connect(view, &BaseView::navigateToPlayer, this,
@@ -520,7 +520,7 @@ QWidget *HomeView::createPersonView(const QString &personId, const QString &pers
connect(view, &BaseView::navigateToPerson, this,
[this](const QString &id, const QString &name) { pushView(createPersonView(id, name)); });
[this](const QString &id, const QString &name) { openPersonRoute(id, name); });
connect(view, &BaseView::navigateToPlayer, this,
@@ -556,10 +556,10 @@ QWidget *HomeView::createSearchView(const QString &query)
[this](const QString &id, const QString &name, const MediaItem &seed) { pushView(createDetailView(id, name, seed)); });
connect(view, &SearchView::navigateToFolder, this,
[this](const QString &id, const QString &name) { pushView(createLibraryView(id, name)); });
[this](const QString &id, const QString &name) { openLibraryRoute(id, name); });
connect(view, &SearchView::navigateToPerson, this,
[this](const QString &id, const QString &name) { pushView(createPersonView(id, name)); });
[this](const QString &id, const QString &name) { openPersonRoute(id, name); });
connect(view, &BaseView::navigateToPlayer, this,
@@ -589,9 +589,9 @@ QWidget *HomeView::createFilteredView(const QString &filterType, const QString &
connect(view, &BaseView::navigateToDetail, this,
[this](const QString &id, const QString &name, const MediaItem &seed) { pushView(createDetailView(id, name, seed)); });
connect(view, &BaseView::navigateToFolder, this,
[this](const QString &id, const QString &name) { pushView(createLibraryView(id, name)); });
[this](const QString &id, const QString &name) { openLibraryRoute(id, name); });
connect(view, &BaseView::navigateToPerson, this,
[this](const QString &id, const QString &name) { pushView(createPersonView(id, name)); });
[this](const QString &id, const QString &name) { openPersonRoute(id, name); });
connect(view, &BaseView::navigateToPlayer, this,
[this](const QString &id, const QString &title, const QString &url, long long ticks,
const QVariant &extraData) { launchPlayer(id, title, url, ticks, extraData); });
@@ -998,7 +998,7 @@ void HomeView::setupSidebar()
{
return;
}
pushView(createLibraryView(viewId, cleanName));
openLibraryRoute(viewId, cleanName);
});
m_sidebarAnim = new QPropertyAnimation(m_sidebar, "pos", this);
@@ -1301,6 +1301,59 @@ bool HomeView::pushQuickRoute(const QVariantMap &request)
return true;
}
void HomeView::openCategoryRoute(const QString &categoryId, const QString &title)
{
const bool favorite = categoryId.startsWith(QLatin1String("Favorite_"));
const QString normalizedId = favorite ? categoryId.mid(9) : categoryId;
const QVariantMap request{
{QStringLiteral("name"), QStringLiteral("category")},
{QStringLiteral("title"), title},
{QStringLiteral("params"),
QVariantMap{{QStringLiteral("categoryId"), normalizedId},
{QStringLiteral("title"), title},
{QStringLiteral("favorite"), favorite}}}};
if (!pushQuickRoute(request))
pushView(createCategoryView(categoryId, title));
}
void HomeView::openLibraryRoute(const QString &libraryId, const QString &title)
{
const QVariantMap request{
{QStringLiteral("name"), QStringLiteral("library")},
{QStringLiteral("title"), title},
{QStringLiteral("params"),
QVariantMap{{QStringLiteral("libraryId"), libraryId},
{QStringLiteral("title"), title}}}};
if (!pushQuickRoute(request))
pushView(createLibraryView(libraryId, title));
}
void HomeView::openPersonRoute(const QString &personId, const QString &title)
{
const QVariantMap request{
{QStringLiteral("name"), QStringLiteral("person")},
{QStringLiteral("title"), title},
{QStringLiteral("params"),
QVariantMap{{QStringLiteral("personId"), personId},
{QStringLiteral("title"), title}}}};
if (!pushQuickRoute(request))
pushView(createPersonView(personId, title));
}
void HomeView::openFilteredRoute(const QString &filterType,
const QString &filterValue)
{
const QVariantMap request{
{QStringLiteral("name"), QStringLiteral("filtered")},
{QStringLiteral("title"), filterValue},
{QStringLiteral("params"),
QVariantMap{{QStringLiteral("filterType"), filterType},
{QStringLiteral("filterValue"), filterValue},
{QStringLiteral("title"), filterValue}}}};
if (!pushQuickRoute(request))
pushView(createFilteredView(filterType, filterValue));
}
void HomeView::navigateBack()
{
QWidget *current = m_contentSwitcher->currentWidget();
+4
View File
@@ -117,6 +117,10 @@ private:
void pushView(QWidget* view);
bool pushQuickRoute(const QVariantMap &request);
void openCategoryRoute(const QString &categoryId, const QString &title);
void openLibraryRoute(const QString &libraryId, const QString &title);
void openPersonRoute(const QString &personId, const QString &title);
void openFilteredRoute(const QString &filterType, const QString &filterValue);
void resetToView(QWidget* view, const QString &rootRoute = QString());
QWidget* homeRootWidget() const;