File indexing completed on 2024-05-12 16:21:30

0001 /**
0002  * SPDX-FileCopyrightText: 2020 Tobias Fella <tobias.fella@kde.org>
0003  * SPDX-FileCopyrightText: 2021 Bart De Vries <bart@mogwai.be>
0004  *
0005  * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0006  */
0007 
0008 #include <QCommandLineOption>
0009 #include <QCommandLineParser>
0010 #include <QIcon>
0011 #include <QLoggingCategory>
0012 #include <QQmlApplicationEngine>
0013 #include <QQmlContext>
0014 #include <QQuickStyle>
0015 #include <QQuickView>
0016 #include <QString>
0017 #include <QStringList>
0018 #include <QSysInfo>
0019 #include <QVariant>
0020 
0021 #ifdef Q_OS_ANDROID
0022 #include <QGuiApplication>
0023 #else
0024 #include <QApplication>
0025 #endif
0026 
0027 #include <KAboutData>
0028 #include <KLocalizedContext>
0029 #include <KLocalizedString>
0030 
0031 #ifdef Q_OS_ANDROID
0032 #include "androidlogging.h"
0033 #endif
0034 #include "audiomanager.h"
0035 #include "author.h"
0036 #include "database.h"
0037 #include "datamanager.h"
0038 #include "entry.h"
0039 #include "feed.h"
0040 #include "fetcher.h"
0041 #include "kasts-version.h"
0042 #include "models/abstractepisodemodel.h"
0043 #include "models/abstractepisodeproxymodel.h"
0044 #include "models/chaptermodel.h"
0045 #include "models/downloadmodel.h"
0046 #include "models/entriesproxymodel.h"
0047 #include "models/episodeproxymodel.h"
0048 #include "models/errorlogmodel.h"
0049 #include "models/feedsproxymodel.h"
0050 #include "models/podcastsearchmodel.h"
0051 #include "models/queuemodel.h"
0052 #include "networkconnectionmanager.h"
0053 #include "settingsmanager.h"
0054 #include "storagemanager.h"
0055 #include "sync/sync.h"
0056 #include "sync/syncutils.h"
0057 #include "systrayicon.h"
0058 
0059 #ifdef Q_OS_WINDOWS
0060 #include <windows.h>
0061 #endif
0062 
0063 #ifdef Q_OS_ANDROID
0064 Q_DECL_EXPORT
0065 #endif
0066 
0067 int main(int argc, char *argv[])
0068 {
0069     if (QSysInfo::currentCpuArchitecture().contains(QStringLiteral("arm")) && qEnvironmentVariableIsEmpty("QT_ENABLE_GLYPH_CACHE_WORKAROUND")) {
0070         qputenv("QT_ENABLE_GLYPH_CACHE_WORKAROUND", "1");
0071     }
0072 
0073 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0074     QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
0075     QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
0076 #endif
0077 
0078 #ifdef Q_OS_ANDROID
0079     QGuiApplication app(argc, argv);
0080     qInstallMessageHandler(myMessageHandler);
0081     QLoggingCategory::setFilterRules(QStringLiteral("org.kde.*=true"));
0082     QQuickStyle::setStyle(QStringLiteral("org.kde.breeze"));
0083 #else
0084     QApplication app(argc, argv);
0085     if (qEnvironmentVariableIsEmpty("QT_QUICK_CONTROLS_STYLE")) {
0086         QQuickStyle::setStyle(QStringLiteral("org.kde.desktop"));
0087     }
0088 #endif
0089 
0090 #ifdef Q_OS_WINDOWS
0091     if (AttachConsole(ATTACH_PARENT_PROCESS)) {
0092         freopen("CONOUT$", "w", stdout);
0093         freopen("CONOUT$", "w", stderr);
0094     }
0095 
0096     QApplication::setStyle(QStringLiteral("breeze"));
0097     auto font = app.font();
0098     font.setPointSize(10);
0099     app.setFont(font);
0100 #endif
0101 
0102     QIcon::setFallbackSearchPaths(QIcon::fallbackSearchPaths() << QStringLiteral(":custom-icons"));
0103 
0104     QCoreApplication::setOrganizationName(QStringLiteral("KDE"));
0105     QCoreApplication::setOrganizationDomain(QStringLiteral("kde.org"));
0106     QCoreApplication::setApplicationName(QStringLiteral("Kasts"));
0107 
0108     QQmlApplicationEngine engine;
0109     engine.rootContext()->setContextObject(new KLocalizedContext(&engine));
0110     KLocalizedString::setApplicationDomain("kasts");
0111 
0112     QCommandLineParser parser;
0113     parser.setApplicationDescription(i18n("Podcast Application"));
0114     QCommandLineOption addFeedOption(QStringList() << QStringLiteral("a") << QStringLiteral("add"),
0115                                      i18n("Adds a new podcast to subscriptions."),
0116                                      i18n("Podcast URL"),
0117                                      QStringLiteral("none"));
0118     parser.addOption(addFeedOption);
0119 
0120     KAboutData about(QStringLiteral("kasts"),
0121                      i18n("Kasts"),
0122                      QStringLiteral(KASTS_VERSION_STRING),
0123                      i18n("Podcast Player"),
0124                      KAboutLicense::GPL,
0125                      i18n("© 2020–2023 KDE Community"));
0126     about.addAuthor(i18n("Tobias Fella"), QString(), QStringLiteral("tobias.fella@kde.org"), QStringLiteral("https://tobiasfella.de"));
0127     about.addAuthor(i18n("Bart De Vries"), QString(), QStringLiteral("bart@mogwai.be"));
0128     about.setProgramLogo(QVariant(QIcon(QStringLiteral(":/logo.svg"))));
0129     KAboutData::setApplicationData(about);
0130 
0131     about.setupCommandLine(&parser);
0132     parser.process(app);
0133     QString feedURL = parser.value(addFeedOption);
0134     if (feedURL != QStringLiteral("none")) {
0135         Database::instance();
0136         DataManager::instance().addFeed(feedURL);
0137     }
0138     about.processCommandLine(&parser);
0139 
0140     qmlRegisterType<FeedsProxyModel>("org.kde.kasts", 1, 0, "FeedsProxyModel");
0141     qmlRegisterType<QueueModel>("org.kde.kasts", 1, 0, "QueueModel");
0142     qmlRegisterType<EpisodeProxyModel>("org.kde.kasts", 1, 0, "EpisodeProxyModel");
0143     qmlRegisterType<PodcastSearchModel>("org.kde.kasts", 1, 0, "PodcastSearchModel");
0144     qmlRegisterType<ChapterModel>("org.kde.kasts", 1, 0, "ChapterModel");
0145 
0146     qmlRegisterUncreatableType<AbstractEpisodeProxyModel>("org.kde.kasts", 1, 0, "AbstractEpisodeProxyModel", QStringLiteral("Only for enums"));
0147     qmlRegisterUncreatableType<EntriesProxyModel>("org.kde.kasts", 1, 0, "EntriesProxyModel", QStringLiteral("Get from Feed"));
0148     qmlRegisterUncreatableType<Enclosure>("org.kde.kasts", 1, 0, "Enclosure", QStringLiteral("Only for enums"));
0149     qmlRegisterUncreatableType<AbstractEpisodeModel>("org.kde.kasts", 1, 0, "AbstractEpisodeModel", QStringLiteral("Only for enums"));
0150     qmlRegisterUncreatableType<FeedsModel>("org.kde.kasts", 1, 0, "FeedsModel", QStringLiteral("Only for enums"));
0151 
0152     qmlRegisterSingletonType("org.kde.kasts", 1, 0, "About", [](QQmlEngine *engine, QJSEngine *) -> QJSValue {
0153         return engine->toScriptValue(KAboutData::applicationData());
0154     });
0155     qmlRegisterSingletonInstance("org.kde.kasts", 1, 0, "Database", &Database::instance());
0156     qmlRegisterSingletonInstance("org.kde.kasts", 1, 0, "NetworkConnectionManager", &NetworkConnectionManager::instance());
0157     qmlRegisterSingletonInstance("org.kde.kasts", 1, 0, "Fetcher", &Fetcher::instance());
0158     qmlRegisterSingletonInstance("org.kde.kasts", 1, 0, "DataManager", &DataManager::instance());
0159     qmlRegisterSingletonInstance("org.kde.kasts", 1, 0, "SettingsManager", SettingsManager::self());
0160     qmlRegisterSingletonInstance("org.kde.kasts", 1, 0, "DownloadModel", &DownloadModel::instance());
0161     qmlRegisterSingletonInstance("org.kde.kasts", 1, 0, "ErrorLogModel", &ErrorLogModel::instance());
0162     qmlRegisterSingletonInstance("org.kde.kasts", 1, 0, "AudioManager", &AudioManager::instance());
0163     qmlRegisterSingletonInstance("org.kde.kasts", 1, 0, "StorageManager", &StorageManager::instance());
0164     qmlRegisterSingletonInstance("org.kde.kasts", 1, 0, "Sync", &Sync::instance());
0165     qmlRegisterSingletonInstance("org.kde.kasts", 1, 0, "SystrayIcon", &SystrayIcon::instance());
0166 
0167     qmlRegisterUncreatableMetaObject(SyncUtils::staticMetaObject, "org.kde.kasts", 1, 0, "SyncUtils", QStringLiteral("Error: only enums and structs"));
0168 
0169     qRegisterMetaType<Entry *>("const Entry*"); // "hack" to make qml understand Entry*
0170     qRegisterMetaType<Feed *>("const Feed*"); // "hack" to make qml understand Feed*
0171     qRegisterMetaType<QVector<SyncUtils::Device>>("QVector<SyncUtils::Device>"); // "hack" to make qml understand QVector of SyncUtils::Device
0172 
0173     // Make sure that settings are saved before the application exits
0174     QObject::connect(&app, &QCoreApplication::aboutToQuit, SettingsManager::self(), &SettingsManager::save);
0175 
0176     engine.load(QUrl(QStringLiteral("qrc:///main.qml")));
0177 
0178     if (engine.rootObjects().isEmpty()) {
0179         return -1;
0180     }
0181 
0182     return app.exec();
0183 }