Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,18 @@ CPMAddPackage(

find_package(PolkitQt6-1 REQUIRED)

# Optional: localized application summaries from the distribution's AppStream
# catalogue. Without it we fall back to the (English-only) pacman pkgdesc.
option(ENABLE_APPSTREAM "Use AppStream metadata for localized descriptions" ON)
if(ENABLE_APPSTREAM)
find_package(AppStreamQt 1.0 QUIET)
if(AppStreamQt_FOUND)
message(STATUS "AppStreamQt found: descriptions will be localized")
else()
message(STATUS "AppStreamQt not found: descriptions will fall back to pkgdesc")
endif()
endif()

##
## CONFIGURATION
##
Expand Down Expand Up @@ -134,6 +146,11 @@ include_directories(${CMAKE_SOURCE_DIR}/src ${CMAKE_BINARY_DIR})

target_link_libraries(${PROJECT_NAME} PRIVATE project_warnings project_options Qt6::Widgets Threads::Threads spdlog::spdlog fmt::fmt ryml::ryml cpr::cpr backend-rustlib-cxxbridge PkgConfig::LIBALPM)

if(AppStreamQt_FOUND)
target_link_libraries(${PROJECT_NAME} PRIVATE AppStreamQt)
target_compile_definitions(${PROJECT_NAME} PRIVATE HAVE_APPSTREAM)
endif()

option(ENABLE_UNITY "Enable Unity builds of projects" OFF)
if(ENABLE_UNITY)
# Add for any project you want to apply unity builds for
Expand Down
56 changes: 53 additions & 3 deletions src/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@
#include <array> // for array
#include <ranges> // for ranges::*

#ifdef HAVE_APPSTREAM
#include <AppStreamQt/component-box.h>
#include <AppStreamQt/component.h>
#include <AppStreamQt/pool.h>
#endif

#include <QCoreApplication>
#include <QFile>
#include <QMenu>
Expand Down Expand Up @@ -133,6 +139,7 @@ void MainWindow::setup() noexcept {
const QString icon = "software-update-available-symbolic";
const QIcon backup_icon = QIcon(":/icons/software-update-available.png");
m_ui->icon->setIcon(QIcon::fromTheme(icon, backup_icon));
loadAppStreamSummaries();
fetch_net_pkglist();
refreshPopularApps();

Expand Down Expand Up @@ -399,6 +406,41 @@ void processMap(MainWindow& window, const std::string& parent_category, ryml::No
}
}

// Collect translated application summaries from the distribution's AppStream
// catalogue, keyed by package name. Does nothing when AppStream is unavailable,
// in which case callers fall back to the English pkgdesc.
void MainWindow::loadAppStreamSummaries() noexcept {
#ifdef HAVE_APPSTREAM
spdlog::debug("+++ {} +++", __PRETTY_FUNCTION__);

AppStream::Pool pool;
// Only the distro catalogue carries <pkgname>; skipping the other sources
// keeps the pass short without losing any package mapping.
pool.setFlags(AppStream::Pool::FlagLoadOsCatalog);
if (!pool.load()) {
spdlog::warn("AppStream metadata unavailable, falling back to pkgdesc: {}", pool.lastError().toStdString());
return;
}

// A single pass over the catalogue is cheaper than one lookup per package.
for (const auto& component : pool.components()) {
const auto& summary = component.summary();
if (summary.isEmpty()) {
continue;
}
const bool is_app = (component.kind() == AppStream::Component::KindDesktopApp);
for (const auto& pkgname : component.packageNames()) {
// A package may be claimed by several components; a desktop
// application describes it better than an addon or a codec.
if (is_app || !m_appstream_summaries.contains(pkgname)) {
m_appstream_summaries.insert(pkgname, summary);
}
}
}
spdlog::debug("AppStream summaries loaded: {}", m_appstream_summaries.size());
#endif
}

// Load data from Github repo
void MainWindow::fetch_net_pkglist() noexcept {
spdlog::debug("+++ {} +++", __PRETTY_FUNCTION__);
Expand Down Expand Up @@ -456,8 +498,13 @@ void MainWindow::processFile(const std::string& group, const std::string& catego
QString install_names;
QString uninstall_names;

if (auto pkg = m_alpm_manager->get_package_view(names[0])) {
description = QString(pkg->desc.data());
// Prefer the AppStream summary, which is translated into the user's
// language; pkgdesc from the pacman database is English only.
description = m_appstream_summaries.value(QString::fromStdString(names[0]));
if (description.isEmpty()) {
if (auto pkg = m_alpm_manager->get_package_view(names[0])) {
description = QString(pkg->desc.data());
}
}

install_names = QString::fromStdString(fmt::format("{} {}", names[0], utils::join_range(names.begin() + 1, names.end(), ' ')));
Expand Down Expand Up @@ -702,7 +749,10 @@ void MainWindow::displayPackages() noexcept {
widget_item->setCheckState(TreeCol::Check, Qt::Unchecked);
widget_item->setText(TreeCol::Name, key);
widget_item->setText(TreeCol::Version, value.at(0));
widget_item->setText(TreeCol::Description, value.at(1));
// Same as for the popular apps: a translated AppStream summary if we
// have one, otherwise the English pkgdesc.
const auto& as_summary = m_appstream_summaries.value(key);
widget_item->setText(TreeCol::Description, as_summary.isEmpty() ? value.at(1) : as_summary);
widget_item->setText(TreeCol::Displayed, QStringLiteral("true")); // all items are displayed till filtered

// update tree
Expand Down
6 changes: 6 additions & 0 deletions src/mainwindow.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
#include <map>
#include <string_view>

#include <QHash>
#include <QProgressDialog>
#include <QSettings>
#include <QTimer>
Expand Down Expand Up @@ -137,6 +138,7 @@ class MainWindow : public QDialog {
void ifDownloadFailed() noexcept;
void listFlatpakRemotes() noexcept;
void listSizeInstalledFP() noexcept;
void loadAppStreamSummaries() noexcept;
void fetch_net_pkglist() noexcept;
void processFile(const std::string& group, const std::string& category, const std::vector<std::string>& names) noexcept;
void refreshPopularApps() noexcept;
Expand Down Expand Up @@ -214,6 +216,10 @@ class MainWindow : public QDialog {

alpm::AlpmManagerPtr m_alpm_manager;

/// Maps a package name to its AppStream summary, translated into the
/// user's language. Empty when no AppStream metadata is available.
QHash<QString, QString> m_appstream_summaries{};

QString m_indexFilterFP{};
bool m_warning_flatpaks{};
bool m_setup_assistant_mode{};
Expand Down