File indexing completed on 2024-04-21 15:43:09

0001 /**
0002  * SPDX-FileCopyrightText: 2018-2019 Black Hat <bhat@encom.eu.org>
0003  *
0004  * SPDX-License-Identifier: GPL-3.0-only
0005  */
0006 #include <QCommandLineParser>
0007 #include <QFontDatabase>
0008 #include <QNetworkProxy>
0009 #include <QNetworkProxyFactory>
0010 #include <QQmlApplicationEngine>
0011 #include <QQmlContext>
0012 #include <QQuickStyle>
0013 #include <QQuickWindow>
0014 #include <clocale>
0015 
0016 #ifdef Q_OS_ANDROID
0017 #include <QGuiApplication>
0018 #else
0019 #include <QApplication>
0020 #endif
0021 
0022 #include <KAboutData>
0023 #ifdef HAVE_KDBUSADDONS
0024 #include <KDBusService>
0025 #include <KWindowSystem>
0026 #endif
0027 #include <KConfig>
0028 #include <KLocalizedContext>
0029 #include <KLocalizedString>
0030 #include <KWindowConfig>
0031 
0032 #include "tokodon-version.h"
0033 
0034 #include "account/account.h"
0035 #include "account/accountmanager.h"
0036 #include "account/profileeditor.h"
0037 #include "account/socialgraphmodel.h"
0038 #include "admin/accounttoolmodel.h"
0039 #include "admin/adminaccountinfo.h"
0040 #include "admin/federationtoolmodel.h"
0041 #include "config.h"
0042 #include "conversation/conversationmodel.h"
0043 #include "editor/attachmenteditormodel.h"
0044 #include "editor/languagemodel.h"
0045 #include "editor/polltimemodel.h"
0046 #include "editor/posteditorbackend.h"
0047 #include "network/networkaccessmanagerfactory.h"
0048 #include "network/networkcontroller.h"
0049 #include "network/networkrequestprogress.h"
0050 #include "search/searchmodel.h"
0051 #include "timeline/accountmodel.h"
0052 #include "timeline/maintimelinemodel.h"
0053 #include "timeline/notificationmodel.h"
0054 #include "timeline/poll.h"
0055 #include "timeline/post.h"
0056 #include "timeline/tagstimelinemodel.h"
0057 #include "timeline/threadmodel.h"
0058 #include "utils/blurhashimageprovider.h"
0059 #include "utils/clipboard.h"
0060 #include "utils/filehelper.h"
0061 #include "utils/mpvplayer.h"
0062 #include "timeline/tagsmodel.h"
0063 
0064 #ifdef HAVE_COLORSCHEME
0065 #include "utils/colorschemer.h"
0066 #endif
0067 
0068 #ifdef Q_OS_WINDOWS
0069 #include <Windows.h>
0070 #endif
0071 
0072 #ifdef Q_OS_ANDROID
0073 Q_DECL_EXPORT
0074 #endif
0075 int main(int argc, char *argv[])
0076 {
0077 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0078     QGuiApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
0079 #endif
0080 
0081     QNetworkProxyFactory::setUseSystemConfiguration(true);
0082 
0083 #ifdef Q_OS_ANDROID
0084     QGuiApplication app(argc, argv);
0085     QQuickStyle::setStyle(QStringLiteral("org.kde.breeze"));
0086     QIcon::setThemeName("tokodon");
0087 #else
0088     QApplication app(argc, argv);
0089     // Default to org.kde.desktop style unless the user forces another style
0090     if (qEnvironmentVariableIsEmpty("QT_QUICK_CONTROLS_STYLE")) {
0091         QQuickStyle::setStyle(QStringLiteral("org.kde.desktop"));
0092     }
0093 
0094     // Breeze theme needs to be the "primary" theme or else icons do not get recolored
0095     // Non-Breeze themes (like Adwaita) do not load our icons properly unless tokodon is the main icon theme.
0096     if (QIcon::themeName() == "breeze") {
0097         QIcon::setFallbackThemeName("tokodon");
0098     } else {
0099         QIcon::setThemeName("tokodon");
0100     }
0101 #endif
0102 
0103 #ifdef Q_OS_WINDOWS
0104     if (AttachConsole(ATTACH_PARENT_PROCESS)) {
0105         freopen("CONOUT$", "w", stdout);
0106         freopen("CONOUT$", "w", stderr);
0107     }
0108 
0109     QApplication::setStyle(QStringLiteral("breeze"));
0110     auto font = app.font();
0111     font.setPointSize(10);
0112     app.setFont(font);
0113 #endif
0114     KLocalizedString::setApplicationDomain("tokodon");
0115 
0116     QCoreApplication::setOrganizationName("KDE");
0117 
0118     KAboutData about(QStringLiteral("tokodon"),
0119                      i18n("Tokodon"),
0120                      QStringLiteral(TOKODON_VERSION_STRING),
0121                      i18n("Mastodon client"),
0122                      KAboutLicense::GPL_V3,
0123                      i18n("© 2021-2023 Carl Schwan, 2021-2023 KDE Community"));
0124     about.addAuthor(i18n("Carl Schwan"), i18n("Maintainer"), QStringLiteral("carl@carlschwan.eu"));
0125     about.setTranslator(i18nc("NAME OF TRANSLATORS", "Your names"), i18nc("EMAIL OF TRANSLATORS", "Your emails"));
0126     about.setOrganizationDomain("kde.org");
0127     about.setBugAddress("https://bugs.kde.org/describecomponents.cgi?product=tokodon");
0128 
0129     KAboutData::setApplicationData(about);
0130     QGuiApplication::setWindowIcon(QIcon::fromTheme(QStringLiteral("org.kde.tokodon")));
0131 
0132     QCommandLineParser parser;
0133     parser.setApplicationDescription(i18n("Client for the decentralized social network: mastodon"));
0134     parser.addPositionalArgument(QStringLiteral("urls"), i18n("Supports web+ap: url scheme"));
0135 
0136     about.setupCommandLine(&parser);
0137     parser.process(app);
0138     about.processCommandLine(&parser);
0139 
0140 #ifdef HAVE_KDBUSADDONS
0141     KDBusService service(KDBusService::Unique);
0142 #endif
0143     auto config = Config::self();
0144 
0145 #ifdef HAVE_COLORSCHEME
0146     ColorSchemer colorScheme;
0147     qmlRegisterSingletonInstance<ColorSchemer>("org.kde.kmasto", 1, 0, "ColorSchemer", &colorScheme);
0148     if (!config->colorScheme().isEmpty()) {
0149         colorScheme.apply(config->colorScheme());
0150     }
0151 #endif
0152 
0153     // Qt sets the locale in the QGuiApplication constructor, but libmpv
0154     // requires the LC_NUMERIC category to be set to "C", so change it back.
0155     setlocale(LC_NUMERIC, "C");
0156 
0157     qmlRegisterSingletonInstance("org.kde.kmasto", 1, 0, "Config", config);
0158     qmlRegisterSingletonInstance("org.kde.kmasto", 1, 0, "Controller", &NetworkController::instance());
0159     qmlRegisterSingletonInstance("org.kde.kmasto", 1, 0, "AccountManager", &AccountManager::instance());
0160     qmlRegisterType<MainTimelineModel>("org.kde.kmasto", 1, 0, "MainTimelineModel");
0161     qmlRegisterType<SearchModel>("org.kde.kmasto", 1, 0, "SearchModel");
0162     qmlRegisterType<SocialGraphModel>("org.kde.kmasto", 1, 0, "SocialGraphModel");
0163     qmlRegisterType<AccountsToolModel>("org.kde.kmasto", 1, 0, "AccountsToolModel");
0164     qmlRegisterType<FederationToolModel>("org.kde.kmasto", 1, 0, "FederationToolModel");
0165     qmlRegisterType<TagsModel>("org.kde.kmasto", 1, 0, "TagsModel");
0166     qmlRegisterType<ThreadModel>("org.kde.kmasto", 1, 0, "ThreadModel");
0167     qmlRegisterType<ConversationModel>("org.kde.kmasto", 1, 0, "ConversationModel");
0168     qmlRegisterType<TagsTimelineModel>("org.kde.kmasto", 1, 0, "TagsTimelineModel");
0169     qmlRegisterType<AccountModel>("org.kde.kmasto", 1, 0, "AccountModel");
0170     qmlRegisterType<ProfileEditorBackend>("org.kde.kmasto", 1, 0, "ProfileEditorBackend");
0171     qmlRegisterType<NetworkRequestProgress>("org.kde.kmasto", 1, 0, "NetworkRequestProgress");
0172     qmlRegisterType<PostEditorBackend>("org.kde.kmasto", 1, 0, "PostEditorBackend");
0173     qmlRegisterType<NotificationModel>("org.kde.kmasto", 1, 0, "NotificationModel");
0174     qmlRegisterType<PollTimeModel>("org.kde.kmasto", 1, 0, "PollTimeModel");
0175     qmlRegisterSingletonInstance("org.kde.kmasto", 1, 0, "Clipboard", new Clipboard);
0176     qmlRegisterSingletonInstance("org.kde.kmasto", 1, 0, "FileHelper", new FileHelper);
0177     qmlRegisterSingletonType("org.kde.kmasto", 1, 0, "About", [](QQmlEngine *engine, QJSEngine *) -> QJSValue {
0178         return engine->toScriptValue(KAboutData::applicationData());
0179     });
0180     qRegisterMetaType<Account *>("Account*");
0181     qRegisterMetaType<FederationInfo>("FederationInfo");
0182     qRegisterMetaType<AbstractAccount *>("AbstractAccount*");
0183     qRegisterMetaType<Identity *>("Identity*");
0184     qRegisterMetaType<AdminAccountInfo *>("AdminAccountInfo*");
0185     qRegisterMetaType<AttachmentEditorModel *>("AttachmentEditorModel*");
0186     qRegisterMetaType<Post *>("Post*");
0187     qRegisterMetaType<Tag *>("Tag*");
0188     qRegisterMetaType<Poll *>("Poll*");
0189     qRegisterMetaType<Card *>("Card*");
0190     qRegisterMetaType<Application *>("Application*");
0191     qRegisterMetaType<QNetworkReply *>("QNetworkReply*");
0192     qRegisterMetaType<Relationship *>("Relationship*");
0193     qmlRegisterUncreatableType<Tag>("org.kde.kmasto", 1, 0, "Tag", "ENUM");
0194     qmlRegisterUncreatableType<Post>("org.kde.kmasto", 1, 0, "Post", "ENUM");
0195     qmlRegisterUncreatableType<AdminAccountInfo>("org.kde.kmasto", 1, 0, "AdminAccountInfo", "ENUM");
0196     qmlRegisterUncreatableType<Attachment>("org.kde.kmasto", 1, 0, "Attachment", "ENUM");
0197     qmlRegisterUncreatableType<Notification>("org.kde.kmasto", 1, 0, "Notification", "ENUM");
0198     qmlRegisterUncreatableType<Poll>("org.kde.kmasto", 1, 0, "Poll", "ENUM");
0199     qmlRegisterSingletonType(QUrl("qrc:/content/ui/Navigation.qml"), "org.kde.kmasto", 1, 0, "Navigation");
0200     qmlRegisterType<LanguageModel>("org.kde.kmasto", 1, 0, "LanguageModel");
0201     qmlRegisterType<MpvPlayer>("org.kde.kmasto", 1, 0, "MpvPlayer");
0202 
0203     QQmlApplicationEngine engine;
0204     engine.rootContext()->setContextObject(new KLocalizedContext(&engine));
0205     QObject::connect(&engine, &QQmlApplicationEngine::quit, &app, &QCoreApplication::quit);
0206 
0207     NetworkAccessManagerFactory namFactory;
0208     engine.setNetworkAccessManagerFactory(&namFactory);
0209 
0210     // Controller::instance().setAboutData(about);
0211 
0212     engine.addImageProvider(QLatin1String("blurhash"), new BlurhashImageProvider);
0213 
0214     engine.load(QUrl(QStringLiteral("qrc:/content/ui/main.qml")));
0215     if (engine.rootObjects().isEmpty()) {
0216         return -1;
0217     }
0218 
0219     if (parser.positionalArguments().length() > 0) {
0220         NetworkController::instance().openWebApLink(parser.positionalArguments()[0]);
0221     }
0222 
0223 #ifdef HAVE_KDBUSADDONS
0224     QObject::connect(&service, &KDBusService::activateRequested, &engine, [&engine](const QStringList &arguments, const QString & /*workingDirectory*/) {
0225         const auto rootObjects = engine.rootObjects();
0226         for (auto obj : rootObjects) {
0227             auto view = qobject_cast<QQuickWindow *>(obj);
0228             if (view) {
0229                 KWindowSystem::updateStartupId(view);
0230                 KWindowSystem::activateWindow(view);
0231 
0232                 if (arguments.isEmpty()) {
0233                     return;
0234                 }
0235 
0236                 auto args = arguments;
0237                 args.removeFirst();
0238 
0239                 if (arguments.length() >= 1) {
0240                     NetworkController::instance().openWebApLink(args[0]);
0241                 }
0242 
0243                 return;
0244             }
0245         }
0246     });
0247     const auto rootObjects = engine.rootObjects();
0248     for (auto obj : rootObjects) {
0249         auto view = qobject_cast<QQuickWindow *>(obj);
0250         if (view) {
0251             KConfig dataResource("data", KConfig::SimpleConfig, QStandardPaths::AppDataLocation);
0252             KConfigGroup windowGroup(&dataResource, "Window");
0253             KWindowConfig::restoreWindowSize(view, windowGroup);
0254             KWindowConfig::restoreWindowPosition(view, windowGroup);
0255             break;
0256         }
0257     }
0258 #endif
0259     return QCoreApplication::exec();
0260 }