diff --git a/assets/images/settings_call_selected.svg b/assets/images/settings_call_selected.svg index 2a517d0f5..5fbdda3ce 100644 --- a/assets/images/settings_call_selected.svg +++ b/assets/images/settings_call_selected.svg @@ -5,7 +5,7 @@ Created with Sketch. - + diff --git a/src/app/App.cpp b/src/app/App.cpp index 2620f89c4..164fa7b48 100644 --- a/src/app/App.cpp +++ b/src/app/App.cpp @@ -106,9 +106,7 @@ App::~App () { // ----------------------------------------------------------------------------- -inline QQuickWindow *createSubWindow (App *app, const char *path) { - QQmlEngine *engine = app->getEngine(); - +inline QQuickWindow *createSubWindow (QQmlApplicationEngine *engine, const char *path) { QQmlComponent component(engine, QUrl(path)); if (component.isError()) { qWarning() << component.errors(); @@ -117,16 +115,16 @@ inline QQuickWindow *createSubWindow (App *app, const char *path) { QObject *object = component.create(); QQmlEngine::setObjectOwnership(object, QQmlEngine::CppOwnership); - object->setParent(app->getEngine()); + object->setParent(engine); return qobject_cast(object); } // ----------------------------------------------------------------------------- -inline void activeSplashScreen (App *app) { +inline void activeSplashScreen (QQmlApplicationEngine *engine) { qInfo() << QStringLiteral("Open splash screen..."); - QQuickWindow *splashScreen = ::createSubWindow(app, QML_VIEW_SPLASH_SCREEN); + QQuickWindow *splashScreen = ::createSubWindow(engine, QML_VIEW_SPLASH_SCREEN); QObject::connect(CoreManager::getInstance()->getHandlers().get(), &CoreHandlers::coreStarted, splashScreen, [splashScreen] { splashScreen->close(); splashScreen->deleteLater(); @@ -176,17 +174,20 @@ void App::initContentApp () { mEngine->addImageProvider(ImageProvider::PROVIDER_ID, new ImageProvider()); mEngine->addImageProvider(ThumbnailProvider::PROVIDER_ID, new ThumbnailProvider()); + mColors = new Colors(this); + registerTypes(); registerSharedTypes(); registerToolTypes(); + registerSharedToolTypes(); // Enable notifications. - createNotifier(); + mNotifier = new Notifier(mEngine); // Load splashscreen. bool selfTest = mParser->isSet("self-test"); if (!selfTest) - ::activeSplashScreen(this); + ::activeSplashScreen(mEngine); // Set a self test limit. else QTimer::singleShot(SELF_TEST_DELAY, this, [] { @@ -224,7 +225,7 @@ void App::executeCommand (const QString &command) { QQuickWindow *App::getCallsWindow () { if (!mCallsWindow) - mCallsWindow = ::createSubWindow(this, QML_VIEW_CALLS_WINDOW); + mCallsWindow = ::createSubWindow(mEngine, QML_VIEW_CALLS_WINDOW); return mCallsWindow; } @@ -237,7 +238,7 @@ QQuickWindow *App::getMainWindow () const { QQuickWindow *App::getSettingsWindow () { if (!mSettingsWindow) { - mSettingsWindow = ::createSubWindow(this, QML_VIEW_SETTINGS_WINDOW); + mSettingsWindow = ::createSubWindow(mEngine, QML_VIEW_SETTINGS_WINDOW); QObject::connect(mSettingsWindow, &QWindow::visibilityChanged, this, [](QWindow::Visibility visibility) { if (visibility == QWindow::Hidden) { qInfo() << QStringLiteral("Update nat policy."); @@ -338,6 +339,15 @@ void registerToolType (const char *name) { }); } +#define registerSharedToolType(TYPE, NAME, METHOD) qmlRegisterSingletonType( \ + NAME, 1, 0, NAME, \ + [](QQmlEngine *, QJSEngine *) -> QObject *{ \ + QObject *object = METHOD(); \ + QQmlEngine::setObjectOwnership(object, QQmlEngine::CppOwnership); \ + return object; \ + } \ +) + void App::registerTypes () { qInfo() << QStringLiteral("Registering types..."); @@ -387,12 +397,18 @@ void App::registerToolTypes () { qInfo() << QStringLiteral("Registering tool types..."); registerToolType("Clipboard"); - registerToolType("Colors"); registerToolType("TextToSpeech"); registerToolType("Units"); } +void App::registerSharedToolTypes () { + qInfo() << QStringLiteral("Registering shared tool types..."); + + registerSharedToolType(Colors, "Colors", App::getInstance()->getColors); +} + #undef registerUncreatableType +#undef registerSharedToolType #undef registerSharedSingletonType // ----------------------------------------------------------------------------- @@ -436,13 +452,6 @@ void App::setTrayIcon () { // ----------------------------------------------------------------------------- -void App::createNotifier () { - if (!mNotifier) - mNotifier = new Notifier(this); -} - -// ----------------------------------------------------------------------------- - void App::initLocale () { // Try to use preferred locale. QString locale; diff --git a/src/app/App.hpp b/src/app/App.hpp index 0f58825b6..ca93868f0 100644 --- a/src/app/App.hpp +++ b/src/app/App.hpp @@ -27,6 +27,7 @@ #include #include "../components/notifier/Notifier.hpp" +#include "../components/other/colors/Colors.hpp" #include "../externals/single-application/SingleApplication.hpp" #define APP_CODE_RESTART 1000 @@ -63,6 +64,10 @@ public: return mNotifier; } + Colors *getColors () const { + return mColors; + } + QQuickWindow *getMainWindow () const; bool hasFocus () const; @@ -92,6 +97,7 @@ private: void registerTypes (); void registerSharedTypes (); void registerToolTypes (); + void registerSharedToolTypes (); void setTrayIcon (); void createNotifier (); @@ -128,6 +134,8 @@ private: QQuickWindow *mCallsWindow = nullptr; QQuickWindow *mSettingsWindow = nullptr; + Colors *mColors = nullptr; + Cli *mCli = nullptr; }; diff --git a/src/app/providers/ImageProvider.cpp b/src/app/providers/ImageProvider.cpp index 2462810b9..d7fdd687b 100644 --- a/src/app/providers/ImageProvider.cpp +++ b/src/app/providers/ImageProvider.cpp @@ -28,6 +28,8 @@ #include #include +#include "../App.hpp" + #include "ImageProvider.hpp" // Max image size in bytes. (100Kb) @@ -35,28 +37,73 @@ // ============================================================================= -const QString ImageProvider::PROVIDER_ID = "internal"; +static QByteArray buildByteArrayAttribute (const QByteArray &name, const QByteArray &value) { + QByteArray attribute = name; + attribute.append("=\""); + attribute.append(value); + attribute.append("\" "); + return attribute; +} -ImageProvider::ImageProvider () : QQuickImageProvider( - QQmlImageProviderBase::Image, - QQmlImageProviderBase::ForceAsynchronousImageLoading - ) {} +static QByteArray fillFillAndStroke (QXmlStreamAttributes &readerAttributes, bool &fill, bool &stroke, const Colors &colors) { + static QRegExp regex("^color-([^-]+)-(fill|stroke)$"); -// ----------------------------------------------------------------------------- - -static QByteArray parseAttributes (QXmlStreamReader &reader) { QByteArray attributes; - for (const auto &attribute : reader.attributes()) { - const QByteArray prefix = attribute.prefix().toLatin1(); + QByteArray value = readerAttributes.value("class").toLatin1(); + if (!value.length()) + return attributes; + + for (const auto &subValue : value.split(' ')) { + regex.indexIn(subValue.trimmed()); + const QStringList list = regex.capturedTexts(); + if (list.length() != 3) + continue; + + const QString colorName = list[1]; + QVariant colorValue = colors.property(colorName.toStdString().c_str()); + if (!colorValue.isValid()) { + qWarning() << QStringLiteral("Color name `%1` does not exist.").arg(colorName); + continue; + } + + QByteArray property = list[2].toLatin1(); + if (property == QStringLiteral("fill")) + fill = true; + else + stroke = true; + + attributes.append( + buildByteArrayAttribute( + property, + colorValue.value().name().toLatin1() + ) + ); + } + + return attributes; +} + +static QByteArray parseAttributes (QXmlStreamReader &reader, const Colors &colors) { + QXmlStreamAttributes readerAttributes = reader.attributes(); + bool fill = false, stroke = false; + QByteArray attributes = fillFillAndStroke(readerAttributes, fill, stroke, colors); + + for (const auto &attribute : readerAttributes) { + QByteArray name = attribute.name().toLatin1(); + if (fill && name == QStringLiteral("fill")) + continue; + if (stroke && name == QStringLiteral("stroke")) + continue; + + QByteArray prefix = attribute.prefix().toLatin1(); + QByteArray value = attribute.value().toLatin1(); + if (prefix.length() > 0) { attributes.append(prefix); attributes.append(":"); } - attributes.append(attribute.name().toLatin1()); - attributes.append("=\""); - attributes.append(attribute.value().toLatin1()); - attributes.append("\" "); + attributes.append(buildByteArrayAttribute(name, value)); } return attributes; @@ -65,7 +112,7 @@ static QByteArray parseAttributes (QXmlStreamReader &reader) { static QByteArray parseDeclarations (QXmlStreamReader &reader) { QByteArray declarations; for (const auto &declaration : reader.namespaceDeclarations()) { - const QByteArray prefix = declaration.prefix().toLatin1(); + QByteArray prefix = declaration.prefix().toLatin1(); if (prefix.length() > 0) { declarations.append("xmlns:"); declarations.append(prefix); @@ -89,11 +136,11 @@ static QByteArray parseStartDocument (QXmlStreamReader &reader) { return startDocument; } -static QByteArray parseStartElement (QXmlStreamReader &reader) { +static QByteArray parseStartElement (QXmlStreamReader &reader, const Colors &colors) { QByteArray startElement = "<"; startElement.append(reader.name().toLatin1()); startElement.append(" "); - startElement.append(parseAttributes(reader)); + startElement.append(parseAttributes(reader, colors)); startElement.append(" "); startElement.append(parseDeclarations(reader)); startElement.append(">"); @@ -110,6 +157,8 @@ static QByteArray parseEndElement (QXmlStreamReader &reader) { // ----------------------------------------------------------------------------- static QByteArray computeContent (QFile &file) { + const Colors *colors = App::getInstance()->getColors(); + QByteArray content; QXmlStreamReader reader(&file); while (!reader.atEnd()) @@ -127,7 +176,7 @@ static QByteArray computeContent (QFile &file) { break; case QXmlStreamReader::StartElement: - content.append(parseStartElement(reader)); + content.append(parseStartElement(reader, *colors)); break; case QXmlStreamReader::EndElement: @@ -148,6 +197,15 @@ static QByteArray computeContent (QFile &file) { // ----------------------------------------------------------------------------- +const QString ImageProvider::PROVIDER_ID = "internal"; + +ImageProvider::ImageProvider () : QQuickImageProvider( + QQmlImageProviderBase::Image, + QQmlImageProviderBase::ForceAsynchronousImageLoading + ) {} + +// ----------------------------------------------------------------------------- + QImage ImageProvider::requestImage (const QString &id, QSize *, const QSize &) { const QString path = QStringLiteral(":/assets/images/%1").arg(id);