/* SPDX-FileCopyrightText: 2026 Project Tick * SPDX-FileContributor: Project Tick * SPDX-License-Identifier: GPL-3.0-or-later * * MeshMC - A Custom Launcher for Minecraft * Copyright (C) 2026 Project Tick * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "ganalytics.h" #include "ganalytics_worker.h" #include "sys.h" #include #include #include #include #include #include #include #include #include #include #include GAnalytics::GAnalytics(const QString& trackingID, const QString& clientID, const int version, QObject* parent) : QObject(parent) { d = new GAnalyticsWorker(this); d->m_trackingID = trackingID; d->m_clientID = clientID; d->m_version = version; } /** * Destructor of class GAnalytics. */ GAnalytics::~GAnalytics() { delete d; } void GAnalytics::setLogLevel(GAnalytics::LogLevel logLevel) { d->m_logLevel = logLevel; } GAnalytics::LogLevel GAnalytics::logLevel() const { return d->m_logLevel; } // SETTER and GETTER void GAnalytics::setViewportSize(const QString& viewportSize) { d->m_viewportSize = viewportSize; } QString GAnalytics::viewportSize() const { return d->m_viewportSize; } void GAnalytics::setLanguage(const QString& language) { d->m_language = language; } QString GAnalytics::language() const { return d->m_language; } void GAnalytics::setAnonymizeIPs(bool anonymize) { d->m_anonymizeIPs = anonymize; } bool GAnalytics::anonymizeIPs() { return d->m_anonymizeIPs; } void GAnalytics::setSendInterval(int milliseconds) { d->m_timer.setInterval(milliseconds); } int GAnalytics::sendInterval() const { return (d->m_timer.interval()); } bool GAnalytics::isEnabled() { return d->m_isEnabled; } void GAnalytics::enable(bool state) { d->enable(state); } int GAnalytics::version() { return d->m_version; } void GAnalytics::setNetworkAccessManager( QNetworkAccessManager* networkAccessManager) { if (d->networkManager != networkAccessManager) { // Delete the old network manager if it was our child if (d->networkManager && d->networkManager->parent() == this) { d->networkManager->deleteLater(); } d->networkManager = networkAccessManager; } } QNetworkAccessManager* GAnalytics::networkAccessManager() const { return d->networkManager; } static void appendCustomValues(QUrlQuery& query, const QVariantMap& customValues) { for (QVariantMap::const_iterator iter = customValues.begin(); iter != customValues.end(); ++iter) { query.addQueryItem(iter.key(), iter.value().toString()); } } /** * Sent screen view is called when the user changed the applications view. * These action of the user should be noticed and reported. Therefore * a QUrlQuery is build in this method. It holts all the parameter for * a http POST. The UrlQuery will be stored in a message Queue. */ void GAnalytics::sendScreenView(const QString& screenName, const QVariantMap& customValues) { d->logMessage(Info, QString("ScreenView: %1").arg(screenName)); QUrlQuery query = d->buildStandardPostQuery("screenview"); query.addQueryItem("cd", screenName); query.addQueryItem("an", d->m_appName); query.addQueryItem("av", d->m_appVersion); appendCustomValues(query, customValues); d->enqueQueryWithCurrentTime(query); } /** * This method is called whenever a button was pressed in the application. * A query for a POST message will be created to report this event. The * created query will be stored in a message queue. */ void GAnalytics::sendEvent(const QString& category, const QString& action, const QString& label, const QVariant& value, const QVariantMap& customValues) { QUrlQuery query = d->buildStandardPostQuery("event"); query.addQueryItem("an", d->m_appName); query.addQueryItem("av", d->m_appVersion); query.addQueryItem("ec", category); query.addQueryItem("ea", action); if (!label.isEmpty()) query.addQueryItem("el", label); if (value.isValid()) query.addQueryItem("ev", value.toString()); appendCustomValues(query, customValues); d->enqueQueryWithCurrentTime(query); } /** * Method is called after an exception was raised. It builds a * query for a POST message. These query will be stored in a * message queue. */ void GAnalytics::sendException(const QString& exceptionDescription, bool exceptionFatal, const QVariantMap& customValues) { QUrlQuery query = d->buildStandardPostQuery("exception"); query.addQueryItem("an", d->m_appName); query.addQueryItem("av", d->m_appVersion); query.addQueryItem("exd", exceptionDescription); if (exceptionFatal) { query.addQueryItem("exf", "1"); } else { query.addQueryItem("exf", "0"); } appendCustomValues(query, customValues); d->enqueQueryWithCurrentTime(query); } /** * Session starts. This event will be sent by a POST message. * Query is setup in this method and stored in the message * queue. */ void GAnalytics::startSession() { QVariantMap customValues; customValues.insert("sc", "start"); sendEvent("Session", "Start", QString(), QVariant(), customValues); } /** * Session ends. This event will be sent by a POST message. * Query is setup in this method and stored in the message * queue. */ void GAnalytics::endSession() { QVariantMap customValues; customValues.insert("sc", "end"); sendEvent("Session", "End", QString(), QVariant(), customValues); } /** * Qut stream to persist class GAnalytics. */ QDataStream& operator<<(QDataStream& outStream, const GAnalytics& analytics) { outStream << analytics.d->persistMessageQueue(); return outStream; } /** * In stream to read GAnalytics from file. */ QDataStream& operator>>(QDataStream& inStream, GAnalytics& analytics) { QList dataList; inStream >> dataList; analytics.d->readMessagesFromFile(dataList); return inStream; }