Files
nearby/sharing/linux/app/main.cc
T

153 lines
4.5 KiB
C++

#include <QDir>
#include <QFileInfo>
#include <QFileSystemWatcher>
#include <QFontDatabase>
#include <QGuiApplication>
#include <QMetaObject>
#include <QObject>
#include <QTimer>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "backend.h"
namespace {
constexpr char kQmlHotReloadEnv[] = "NEARBY_QML_HOT_RELOAD";
constexpr char kQmlSourceDirEnv[] = "NEARBY_QML_SOURCE_DIR";
constexpr char kDefaultQmlSourceDir[] =
"/home/lasan/Dev/nearby_latest/sharing/linux/app";
bool IsHotReloadEnabled() {
const QByteArray value = qgetenv(kQmlHotReloadEnv);
return value == "1" || value.toLower() == "true";
}
QDir QmlSourceDir() {
const QByteArray configured_dir = qgetenv(kQmlSourceDirEnv);
if (!configured_dir.isEmpty()) {
return QDir(QString::fromLocal8Bit(configured_dir));
}
return QDir(QString::fromUtf8(kDefaultQmlSourceDir));
}
void WatchQmlFiles(QFileSystemWatcher& watcher, const QDir& source_dir) {
const QStringList existing_files = watcher.files();
if (!existing_files.isEmpty()) {
watcher.removePaths(existing_files);
}
const QStringList files =
source_dir.entryList(QStringList() << "*.qml", QDir::Files, QDir::Name);
for (const QString& file : files) {
watcher.addPath(source_dir.absoluteFilePath(file));
}
}
void DestroyRootObjects(QQmlApplicationEngine& engine) {
const QList<QObject*> root_objects = engine.rootObjects();
for (QObject* object : root_objects) {
object->deleteLater();
}
}
bool ReloadInnerContent(QQmlApplicationEngine& engine) {
const QList<QObject*> root_objects = engine.rootObjects();
if (root_objects.isEmpty()) {
return false;
}
QObject* root = root_objects.constFirst();
return QMetaObject::invokeMethod(root, "reloadInnerContent");
}
bool RequiresFullReload(const QFileInfo& changed_file) {
return changed_file.fileName() == QStringLiteral("main.qml");
}
} // namespace
int main(int argc, char* argv[]) {
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
const int fontId = QFontDatabase::addApplicationFont(":/googlesans_var.ttf");
if (fontId != -1) {
const QStringList fontFamilies =
QFontDatabase::applicationFontFamilies(fontId);
if (!fontFamilies.isEmpty()) {
const QFont defaultFont(fontFamilies.at(0));
app.setFont(defaultFont);
}
}
if (IsHotReloadEnabled()) {
const QDir qml_source_dir = QmlSourceDir();
const QUrl source_url =
QUrl::fromLocalFile(qml_source_dir.absoluteFilePath("main.qml"));
QFileSystemWatcher watcher;
QTimer reload_timer;
reload_timer.setSingleShot(true);
reload_timer.setInterval(75);
QString changed_path;
const auto fullReload = [&engine, &watcher, qml_source_dir, source_url]() {
WatchQmlFiles(watcher, qml_source_dir);
DestroyRootObjects(engine);
engine.clearComponentCache();
engine.load(source_url);
};
const auto reload = [&engine, &watcher, qml_source_dir, source_url,
&changed_path, &fullReload]() {
WatchQmlFiles(watcher, qml_source_dir);
const QFileInfo changed_file(changed_path);
if (RequiresFullReload(changed_file) || engine.rootObjects().isEmpty()) {
fullReload();
return;
}
engine.clearComponentCache();
if (!ReloadInnerContent(engine)) {
fullReload();
}
};
QObject::connect(&reload_timer, &QTimer::timeout, &app, reload);
QObject::connect(&watcher, &QFileSystemWatcher::fileChanged, &app,
[&reload_timer, &changed_path](const QString& path) {
changed_path = path;
reload_timer.start();
});
QObject::connect(&watcher, &QFileSystemWatcher::directoryChanged, &app,
[&reload_timer, &changed_path](const QString& path) {
changed_path = path;
reload_timer.start();
});
watcher.addPath(qml_source_dir.absolutePath());
fullReload();
return app.exec();
}
// 1. Create the backend instance in C++
Backend backend;
// 2. Inject it into the QML root context
engine.rootContext()->setContextProperty("backend", &backend);
// Loaded via the qrc scheme since it's compiled into the binary
const QUrl url(QStringLiteral("qrc:/main.qml"));
QObject::connect(
&engine, &QQmlApplicationEngine::objectCreated, &app,
[url](QObject* obj, const QUrl& objUrl) {
if (!obj && url == objUrl) QCoreApplication::exit(-1);
},
Qt::QueuedConnection);
engine.load(url);
return app.exec();
}