Initial QSfera import

This commit is contained in:
Курнат Андрей
2026-06-07 10:20:04 +03:00
commit 2315f25754
16485 changed files with 4826827 additions and 0 deletions
+54
View File
@@ -0,0 +1,54 @@
add_library(QSferaResources SHARED
client.qrc
core_theme.qrc
loadresources.cpp
resources.cpp
qmlresources.cpp
themewatcher.cpp
template.cpp
fonticon.cpp
)
generate_theme(QSferaResources QSFERA_SIDEBAR_ICONS)
# make them available to the whole project
set(QSFERA_SIDEBAR_ICONS ${QSFERA_SIDEBAR_ICONS} CACHE INTERNAL "Sidebar icons" FORCE)
target_link_libraries(QSferaResources PUBLIC Qt::Core Qt::Gui Qt::Quick)
apply_common_target_settings(QSferaResources)
target_include_directories(QSferaResources PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/..> $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/..>)
target_compile_definitions(QSferaResources PRIVATE APPLICATION_SHORTNAME="${APPLICATION_SHORTNAME}")
set_target_properties(QSferaResources PROPERTIES
OUTPUT_NAME "QSferaResources"
AUTOUIC ON
AUTORCC ON
VERSION ${MIRALL_VERSION}
SOVERSION ${MIRALL_SOVERSION}
)
generate_export_header(QSferaResources
EXPORT_MACRO_NAME QSFERA_RESOURCES_EXPORT
EXPORT_FILE_NAME qsferaresourceslib.h
STATIC_DEFINE QSFERA_BUILT_AS_STATIC
)
# Handle Translations, pick all desktop_*.ts files from translations directory.
file(GLOB desktop_translations ${CMAKE_SOURCE_DIR}/translations/desktop_*.ts)
qt_add_lrelease(QSferaResources TS_FILES ${desktop_translations} QM_FILES_OUTPUT_VARIABLE desktop_compiled_translations)
add_resources_to_target(
TARGET QSferaResources
PREFIX translations
FILES "${desktop_compiled_translations}"
)
ecm_add_qml_module(QSferaResources
URI eu.QSfera.resources
VERSION 1.0
NAMESPACE OCC
GENERATE_PLUGIN_SOURCE
)
ecm_finalize_qml_module(QSferaResources DESTINATION ${KDE_INSTALL_QMLDIR})
install(TARGETS QSferaResources EXPORT ${APPLICATION_SHORTNAME}Config ${KDE_INSTALL_TARGETS_DEFAULT_ARGS})
+8
View File
@@ -0,0 +1,8 @@
<RCC>
<qresource prefix="/client">
<file alias="resources/wizard/style.qss">wizard/style.qss</file>
<file alias="resources/oauth/oauth.html.in">oauth/oauth.html.in</file>
<file>font-awesome/Font Awesome 6 Free-Solid-900.otf</file>
<file>remixicon/remixicon.ttf</file>
</qresource>
</RCC>
+25
View File
@@ -0,0 +1,25 @@
<RCC>
<qresource prefix="/client/QSfera">
<file alias="theme/dark-systray/error.svg">theme/dark-systray/ocl-ui_error-flieder-colour.svg</file>
<file alias="theme/dark-systray/information.svg">theme/dark-systray/ocl-ui_info-flieder-colour.svg</file>
<file alias="theme/dark-systray/ok.svg">theme/universal/qsfera-icon.svg</file>
<file alias="theme/dark-systray/offline.svg">theme/dark-systray/ocl-ui_offline-flieder-colour.svg</file>
<file alias="theme/dark-systray/pause.svg">theme/dark-systray/ocl-ui_pause-flieder-colour.svg</file>
<file alias="theme/dark-systray/sync.svg">theme/dark-systray/ocl-ui_sync-flieder-colour.svg</file>
<file alias="theme/light-systray/error.svg">theme/light-systray/ocl-ui_error-petrol-colour.svg</file>
<file alias="theme/light-systray/information.svg">theme/light-systray/ocl-ui_info-petrol-colour.svg</file>
<file alias="theme/light-systray/ok.svg">theme/universal/qsfera-icon.svg</file>
<file alias="theme/light-systray/offline.svg">theme/light-systray/ocl-ui_offline-petrol-colour.svg</file>
<file alias="theme/light-systray/pause.svg">theme/light-systray/ocl-ui_pause-petrol-colour.svg</file>
<file alias="theme/light-systray/sync.svg">theme/light-systray/ocl-ui_sync-petrol-colour.svg</file>
<file alias="theme/mask-systray/error.svg">theme/mask-systray/ocl-ui_error-hex#000.svg</file>
<file alias="theme/mask-systray/information.svg">theme/mask-systray/ocl-ui_info-hex#000.svg</file>
<file alias="theme/mask-systray/ok.svg">theme/universal/qsfera-icon-sidebar.svg</file>
<file alias="theme/mask-systray/offline.svg">theme/mask-systray/ocl-ui_offline-hex#000.svg</file>
<file alias="theme/mask-systray/pause.svg">theme/mask-systray/ocl-ui_pause-hex#000.svg</file>
<file alias="theme/mask-systray/sync.svg">theme/mask-systray/ocl-ui_sync-hex#000.svg</file>
<file>theme/universal/qsfera-icon.svg</file>
<file>theme/universal/wizard_logo.svg</file>
<file>theme/universal/sync-exclude.lst</file>
</qresource>
</RCC>
@@ -0,0 +1,34 @@
Font Awesome Free License
-------------------------
Font Awesome Free is free, open source, and GPL friendly. You can use it for
commercial projects, open source projects, or really almost whatever you want.
Full Font Awesome Free license: https://fontawesome.com/license/free.
# Icons: CC BY 4.0 License (https://creativecommons.org/licenses/by/4.0/)
In the Font Awesome Free download, the CC BY 4.0 license applies to all icons
packaged as SVG and JS file types.
# Fonts: SIL OFL 1.1 License (https://scripts.sil.org/OFL)
In the Font Awesome Free download, the SIL OFL license applies to all icons
packaged as web and desktop font files.
# Code: MIT License (https://opensource.org/licenses/MIT)
In the Font Awesome Free download, the MIT license applies to all non-font and
non-icon files.
# Attribution
Attribution is required by MIT, SIL OFL, and CC BY licenses. Downloaded Font
Awesome Free files already contain embedded comments with sufficient
attribution, so you shouldn't need to do anything additional when using these
files normally.
We've kept attribution comments terse, so we ask that you do not actively work
to remove them from files, especially code. They're a great way for folks to
learn about Font Awesome.
# Brand Icons
All brand icons are trademarks of their respective owners. The use of these
trademarks does not indicate endorsement of the trademark holder by Font
Awesome, nor vice versa. **Please do not use brand logos for any purpose except
to represent the company, product, or service to which they refer.**
+116
View File
@@ -0,0 +1,116 @@
// SPDX-License-Identifier: GPL-2.0-or-later
// SPDX-FileCopyrightText: 2025 Hannah von Reth <h.vonreth@opencloud.eu>
#include "fonticon.h"
#include "resources.h"
#include <QIconEngine>
#include <QPainter>
#include <QPixmapCache>
using namespace OCC::Resources;
namespace {
class FontIconEngine : public QIconEngine
{
public:
FontIconEngine(FontIcon::FontFamily family, QChar glyph, FontIcon::Size size, const QColor &color)
: _family(family)
, _glyph(glyph)
, _size(size)
, _color(color.isValid() ? color : OCC::Resources::tint())
{
}
void paint(QPainter *painter, const QRect &rect, QIcon::Mode, QIcon::State) override
{
painter->save();
painter->setRenderHint(QPainter::Antialiasing);
auto pen = painter->pen();
pen.setColor(_color);
painter->setPen(pen);
auto font = painter->font();
switch (_family) {
case FontIcon::FontFamily::FontAwesome:
font.setFamily(QStringLiteral("Font Awesome 6 Free"));
break;
case FontIcon::FontFamily::RemixIcon:
font.setFamily(QStringLiteral("remixicon"));
break;
}
switch (_size) {
case FontIcon::Size::Normal:
font.setPixelSize(rect.height());
break;
case FontIcon::Size::Half:
font.setPixelSize(rect.height() / 2.0);
break;
}
// inspired by https://github.com/gamecreature/QtAwesome/
const auto flags = Qt::AlignHCenter | Qt::AlignVCenter;
QFontMetricsF metrics(font);
QRectF boundingRect = metrics.boundingRect(rect, flags, _glyph);
if (boundingRect.width() > rect.width()) {
auto drawSize =
static_cast<int>(font.pixelSize() * qMin(rect.width() * 0.95 / boundingRect.width(), metrics.height() * 0.95 / boundingRect.height()));
font.setPixelSize(drawSize);
}
painter->setFont(font);
painter->drawText(rect, flags, _glyph);
painter->restore();
}
QPixmap pixmap(const QSize &size, QIcon::Mode mode, QIcon::State state) override
{
QPixmap pixmap;
const QString key = pixmapKey(size, mode, state);
if (QPixmapCache::find(key, &pixmap)) {
return pixmap;
}
pixmap = QPixmap(size);
pixmap.fill(Qt::transparent);
QPainter painter(&pixmap);
paint(&painter, {{0, 0}, size}, mode, state);
painter.end();
QPixmapCache::insert(key, pixmap);
return pixmap;
}
QIconEngine *clone() const override { return new FontIconEngine(this->_family, this->_glyph, this->_size, this->_color); }
QString pixmapKey(const QSize &size, QIcon::Mode mode, QIcon::State state)
{
return QStringLiteral("FontIcon:%1").arg(QString::number(qHashMulti(0, _family, _glyph, _size, _color.rgb(), size, mode, state), 16));
}
const FontIcon::FontFamily _family;
const QChar _glyph;
const FontIcon::Size _size;
const QColor _color;
};
}
FontIcon::FontIcon() { }
FontIcon::FontIcon(QChar glyphe, Size size, const QColor &color)
: QIcon(new FontIconEngine(FontFamily::FontAwesome, glyphe, size, color))
{
}
FontIcon::FontIcon(DefaultGlyphes glyphe, Size size, const QColor &color)
: FontIcon(static_cast<std::underlying_type_t<DefaultGlyphes>>(glyphe), size, color)
{
}
FontIcon::FontIcon(FontFamily family, QChar glyphe, Size size, const QColor &color)
: QIcon(new FontIconEngine(family, glyphe, size, color))
{
}
+58
View File
@@ -0,0 +1,58 @@
// SPDX-License-Identifier: GPL-2.0-or-later
// SPDX-FileCopyrightText: 2025 Hannah von Reth <h.vonreth@opencloud.eu>
#pragma once
#include "qsferaresourceslib.h"
#include <QIcon>
#include <QtQmlIntegration/QtQmlIntegration>
namespace OCC::Resources {
class QSFERA_RESOURCES_EXPORT FontIcon : public QIcon
{
Q_GADGET
QML_VALUE_TYPE(fontIcon)
public:
enum class DefaultGlyphes : char16_t {
Question = u'',
Warning = u'',
Info = u''
};
Q_ENUM(DefaultGlyphes)
enum class FontFamily : uint8_t {
FontAwesome,
RemixIcon,
};
Q_ENUM(FontFamily)
enum class Size : uint8_t {
// fullsized icon
Normal,
// hafl sized, centered icon
Half
};
Q_ENUM(Size)
FontIcon();
// defaults to fontawesoem
FontIcon(QChar glyphe, Size size = Size::Normal, const QColor &color = {});
FontIcon(DefaultGlyphes glyphe, Size size = Size::Normal, const QColor &color = {});
FontIcon(FontFamily family, QChar glyphe, Size size = Size::Normal, const QColor &color = {});
};
// expose the enums to qml
class FontIconDerived : public FontIcon
{
Q_GADGET
};
namespace FontIconDerivedForeign {
Q_NAMESPACE
QML_NAMED_ELEMENT(FontIcon)
QML_FOREIGN_NAMESPACE(Resources::FontIconDerived)
}
}
+38
View File
@@ -0,0 +1,38 @@
#include "loadresources.h"
#include <qglobal.h>
using namespace OCC;
void static load_rc()
{
Q_INIT_RESOURCE(QSferaResources_translations);
Q_INIT_RESOURCE(client);
Q_INIT_RESOURCE(core_theme);
#ifdef BRANDING_AVAILABLE
Q_INIT_RESOURCE(theme);
#endif
}
void static unload_rc()
{
Q_CLEANUP_RESOURCE(QSferaResources_translations);
Q_CLEANUP_RESOURCE(client);
Q_CLEANUP_RESOURCE(core_theme);
#ifdef BRANDING_AVAILABLE
Q_CLEANUP_RESOURCE(theme);
#endif
}
ResourcesLoader::ResourcesLoader()
{
// Q_INIT_RESOURCE must not be called in a namespace
::load_rc();
}
ResourcesLoader::~ResourcesLoader()
{
// Q_CLEANUP_RESOURCE must not be called in a namespace
::unload_rc();
}
+12
View File
@@ -0,0 +1,12 @@
#pragma once
#include "qsferaresourceslib.h"
namespace OCC {
class QSFERA_RESOURCES_EXPORT ResourcesLoader
{
public:
ResourcesLoader();
~ResourcesLoader();
};
}
+43
View File
@@ -0,0 +1,43 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>@{TITLE}</title>
<style>
html, body {
height: 100%;
width: 100%;
margin: 0;
}
body {
background-color: @{BACKGROUND_COLOR};
color: @{FONT_COLOR};
font-family: QSfera, "Noto Sans", OpenSans, Verdana, Helvetica, Arial, sans-serif;
display: flex;
flex-direction: column;
align-items: center;
}
.row {
display: flex;
flex-direction: row;
align-items: center;
height: 100%;
}
.content {
text-align: center;
}
</style>
</head>
<body>
<div class="row">
<div class="content">
<img src="data:image/svg+xml;base64,@{ICON}" />
@{CONTENT}
</div>
</div>
</body>
+42
View File
@@ -0,0 +1,42 @@
/*
* Copyright (C) by Hannah von Reth <hannah.vonreth@owncloud.com>
*
* 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 2 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.
*/
#include "resources/qmlresources.h"
using namespace Qt::Literals::StringLiterals;
namespace {
constexpr QSize minIconSize{16, 16};
}
using namespace OCC;
Resources::Icon Resources::parseIcon(const QString &id)
{
const auto data = QUrlQuery(id);
return {data.queryItemValue("theme"_L1), QUrl::fromPercentEncoding(data.queryItemValue("icon"_L1).toUtf8()),
static_cast<FontIcon::Size>(data.queryItemValue("size"_L1).toInt()), data.queryItemValue("enabled"_L1) == "true"_L1,
QColor(data.queryItemValue("color"_L1))};
}
QPixmap Resources::pixmap(const QSize &requestedSize, const QIcon &icon, QIcon::Mode mode, QSize *outSize)
{
Q_ASSERT(requestedSize.isValid());
QSize actualSize = requestedSize.isValid() ? requestedSize : icon.availableSizes().constFirst();
if (outSize) {
*outSize = actualSize;
}
return icon.pixmap(actualSize.expandedTo(minIconSize), mode);
}
+38
View File
@@ -0,0 +1,38 @@
/*
* Copyright (C) by Hannah von Reth <hannah.vonreth@owncloud.com>
*
* 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 2 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.
*/
#pragma once
#include "resources/qsferaresourceslib.h"
#include "resources/fonticon.h"
#include <QIcon>
#include <QtQml/QtQml>
namespace OCC {
namespace Resources {
struct Icon
{
QString theme;
QString iconName;
FontIcon::Size size;
bool enabled;
QColor color;
};
Icon QSFERA_RESOURCES_EXPORT parseIcon(const QString &id);
QPixmap QSFERA_RESOURCES_EXPORT pixmap(const QSize &requestedSize, const QIcon &icon, QIcon::Mode mode, QSize *outSize);
} // Resources
} // OCC
+201
View File
@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Binary file not shown.
+161
View File
@@ -0,0 +1,161 @@
/*
* Copyright (C) by Hannah von Reth <hannah.vonreth@owncloud.com>
*
* 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 2 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.
*/
#include "resources/resources.h"
#include "fonticon.h"
#include "resources/qmlresources.h"
#include "resources/template.h"
#include "resources/themewatcher.h"
#include "libsync/common/asserts.h"
#include <QDebug>
#include <QFileInfo>
#include <QImageReader>
#include <QJsonDocument>
#include <QLoggingCategory>
#include <QPalette>
using namespace OCC;
using namespace Resources;
Q_LOGGING_CATEGORY(lcResources, "sync.resoruces", QtInfoMsg)
namespace {
struct IconCache
{
IconCache()
{
auto *watcher = new ThemeWatcher(qApp);
QObject::connect(watcher, &ThemeWatcher::themeChanged, qApp, [this]() { _cache.clear(); });
}
QMap<QString, QIcon> _cache;
QTemporaryDir tmpDir;
};
Q_GLOBAL_STATIC(IconCache, iconCache)
QString vanillaThemePath()
{
return QStringLiteral(":/client/QSfera/theme");
}
QString brandThemePath()
{
return QStringLiteral(":/client/" APPLICATION_SHORTNAME "/theme");
}
}
bool Resources::isVanillaTheme()
{
return std::string_view(APPLICATION_SHORTNAME).starts_with("QSfera");
}
bool OCC::Resources::isUsingDarkTheme()
{
return QPalette().base().color().lightnessF() <= 0.5;
}
/*
* helper to load a icon from either the icon theme the desktop provides or from
* the apps Qt resources.
*/
QIcon OCC::Resources::loadIcon(const QString &flavor, const QString &name, IconType iconType)
{
// prevent recusion
const bool useCoreIcon = (iconType == IconType::VanillaIcon) || isVanillaTheme();
const QString path = QStringLiteral("%1/%2/%3").arg(useCoreIcon ? vanillaThemePath() : brandThemePath(), flavor, name);
QIcon &cached = iconCache->_cache[path]; // Take reference, this will also "set" the cache entry
if (cached.isNull()) {
const QString svg = QStringLiteral("%1.svg").arg(path);
if (QFile::exists(svg)) {
return cached = QIcon(svg);
}
const QString png = QStringLiteral("%1.png").arg(path);
if (QFile::exists(png)) {
return cached = QIcon(png);
}
const QList<int> sizes{16, 22, 32, 48, 64, 128, 256, 512, 1024};
QString previousIcon;
for (int size : sizes) {
QString pixmapName = QStringLiteral("%1-%2.png").arg(path, QString::number(size));
if (QFile::exists(pixmapName)) {
previousIcon = pixmapName;
cached.addFile(pixmapName, {size, size});
} else if (size >= 128) {
if (!previousIcon.isEmpty()) {
qCWarning(lcResources) << u"Upscaling:" << previousIcon << u"to" << size;
cached.addPixmap(QPixmap(previousIcon).scaled({size, size}, Qt::KeepAspectRatio, Qt::SmoothTransformation));
}
}
}
}
if (cached.isNull()) {
if (!useCoreIcon && iconType == IconType::BrandedIconWithFallbackToVanillaIcon) {
return loadIcon(flavor, name, IconType::VanillaIcon);
}
qCWarning(lcResources) << u"Failed to locate the icon" << path;
Q_ASSERT(false);
}
return cached;
}
QColor Resources::tint()
{
static QColor lilac{"#E2BAFF"};
static QColor petrol{"#20434F"};
return isUsingDarkTheme() ? lilac : petrol;
}
QIcon OCC::Resources::themeUniversalIcon(const QString &name, IconType iconType)
{
return loadIcon(QStringLiteral("universal"), name, iconType);
}
CoreImageProvider::CoreImageProvider()
: QQuickImageProvider(QQuickImageProvider::Pixmap)
{
}
QPixmap CoreImageProvider::requestPixmap(const QString &id, QSize *size, const QSize &requestedSize)
{
const auto qmlIcon = parseIcon(id);
if (qmlIcon.iconName.isEmpty()) {
return {};
}
QIcon icon;
if (qmlIcon.theme == QLatin1String("universal")) {
icon = themeUniversalIcon(qmlIcon.iconName);
} else if (qmlIcon.theme == QLatin1String("fontawesome")) {
Q_ASSERT(qmlIcon.iconName.length() == 1);
icon = FontIcon(qmlIcon.iconName.front(), qmlIcon.size, qmlIcon.color);
} else if (qmlIcon.theme == QLatin1String("remixicons")) {
Q_ASSERT(qmlIcon.iconName.length() == 1);
icon = FontIcon(FontIcon::FontFamily::RemixIcon, qmlIcon.iconName.front(), qmlIcon.size, qmlIcon.color);
}
return pixmap(requestedSize, icon, qmlIcon.enabled ? QIcon::Normal : QIcon::Disabled, size);
}
QUrl Resources::iconToFileSystemUrl(const QIcon &icon, QAnyStringView type)
{
QFileInfo info(QStringLiteral("%1/%2.%3").arg(iconCache->tmpDir.path(), QString::number(icon.cacheKey()), type.toString()));
if (!info.exists()) {
if (!icon.pixmap(icon.actualSize({512, 512})).save(info.absoluteFilePath())) {
qCWarning(lcResources) << u"Failed to save icon to " << info.absoluteFilePath() << info.size();
}
}
return QUrl::fromLocalFile(info.absoluteFilePath());
}
+63
View File
@@ -0,0 +1,63 @@
/*
* Copyright (C) by Hannah von Reth <hannah.vonreth@owncloud.com>
*
* 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 2 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.
*/
#pragma once
#include "resources/qsferaresourceslib.h"
#include <QIcon>
#include <QUrl>
#include <QtQuick/QQuickImageProvider>
namespace OCC::Resources {
Q_NAMESPACE_EXPORT(QSFERA_RESOURCES_EXPORT)
/**
* Wehther we allow a fallback to a vanilla icon
*/
enum class IconType { BrandedIcon, BrandedIconWithFallbackToVanillaIcon, VanillaIcon };
Q_ENUM_NS(IconType);
/**
*
* @return Whether we are using the vanilla theme
*/
bool QSFERA_RESOURCES_EXPORT isVanillaTheme();
/**
* Whether use the dark icon theme
* The function also ensures the theme supports the dark theme
*/
bool QSFERA_RESOURCES_EXPORT isUsingDarkTheme();
QIcon QSFERA_RESOURCES_EXPORT loadIcon(const QString &flavor, const QString &name, IconType iconType);
QColor QSFERA_RESOURCES_EXPORT tint();
/**
* Returns a universal (non color schema aware) icon.
*/
QIcon QSFERA_RESOURCES_EXPORT themeUniversalIcon(const QString &name, IconType iconType = IconType::BrandedIcon);
class QSFERA_RESOURCES_EXPORT CoreImageProvider : public QQuickImageProvider
{
Q_OBJECT
public:
CoreImageProvider();
QPixmap requestPixmap(const QString &id, QSize *size, const QSize &requestedSize) override;
};
QUrl QSFERA_RESOURCES_EXPORT iconToFileSystemUrl(const QIcon &icon, QAnyStringView type = QStringLiteral("png"));
}
+65
View File
@@ -0,0 +1,65 @@
/*
* Copyright (C) by Hannah von Reth <hannah.vonreth@owncloud.com>
*
* 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 2 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.
*/
#include "template.h"
#include "libsync/common/asserts.h"
#include <QFile>
#include <QFileInfo>
#include <QLoggingCategory>
#include <QRegularExpression>
using namespace OCC::Resources;
Q_LOGGING_CATEGORY(lcResourcesTeplate, "sync.resoruces.template", QtInfoMsg)
QString Template::renderTemplateFromFile(const QString &filePath, const QMap<QAnyStringView, QAnyStringView> &values)
{
return renderTemplate(
[&] {
QFile f(filePath);
OC_ASSERT(f.open(QFile::ReadOnly));
return QString::fromUtf8(f.readAll());
}(),
values);
}
QString Template::renderTemplate(QString &&templ, const QMap<QAnyStringView, QAnyStringView> &values)
{
static const QRegularExpression pattern(QStringLiteral("@{([^{}]+)}"));
const auto replace = [&templ, &values](QRegularExpressionMatchIterator it) {
while (it.hasNext()) {
const auto match = it.next();
Q_ASSERT(match.lastCapturedIndex() == 1);
Q_ASSERT([&] {
if (!values.contains(match.captured(1))) {
qWarning(lcResourcesTeplate) << u"Unknown key:" << match.captured(1);
return false;
}
return true;
}());
templ.replace(match.captured(0), values.value(match.captured(1)).toString());
}
};
auto matches = pattern.globalMatch(templ);
do {
replace(matches);
// the placeholder can again contain a placeholder
matches = pattern.globalMatch(templ);
} while (matches.hasNext());
return templ;
}
+32
View File
@@ -0,0 +1,32 @@
/*
* Copyright (C) by Hannah von Reth <hannah.vonreth@owncloud.com>
*
* 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 2 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.
*/
#pragma once
#include "resources/qsferaresourceslib.h"
#include <QUrl>
namespace OCC {
namespace Resources {
namespace Template {
/**
* Replace all occurances of @{} values in template with the values from values
*/
QSFERA_RESOURCES_EXPORT QString renderTemplateFromFile(const QString &filePath, const QMap<QAnyStringView, QAnyStringView> &values);
QSFERA_RESOURCES_EXPORT QString renderTemplate(QString &&templ, const QMap<QAnyStringView, QAnyStringView> &values);
};
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 353 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 845 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 539 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 734 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

@@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><polygon points="5.39 10.21 5.98 9.87 5.98 7.41 8.1 6.19 8.1 5.52 7.51 5.18 5.38 6.41 3.28 5.19 2.69 5.53 2.69 6.21 4.81 7.43 4.81 9.87 5.39 10.21" fill="#e2baff" stroke-width="0"/><polygon points="10.79 3.11 5.39 0 5.39 0 5.39 0 0 3.11 0 4.47 5.39 1.36 10.79 4.47 10.79 3.11" fill="#e2baff" stroke-width="0"/><path d="M5.4,12.65L0,9.53v1.36l5.4,3.11,1.67-.96v-1.37l-1.67.98Z" fill="#e2baff" stroke-width="0"/><path d="M11.53,5.5l-4.46,2.59v5.34l.73.41h.01l3.72,2.16,4.47-2.58v-5.33l-4.47-2.59ZM13.54,13.51l-1.99-1.99-1.99,1.99-.75-.76,1.99-1.99-1.98-1.97.76-.76,1.97,1.98,1.98-1.98.75.76-1.97,1.97,1.99,1.99-.76.76Z" fill="#f1554c" stroke-width="0"/><polygon points="14.3 12.75 13.54 13.51 11.55 11.52 9.56 13.51 8.81 12.75 10.8 10.76 8.82 8.79 9.58 8.03 11.55 10.01 13.53 8.03 14.28 8.79 12.31 10.76 14.3 12.75" fill="#fff" stroke-width="0"/><polygon points="14.3 12.75 13.54 13.51 11.55 11.52 9.56 13.51 8.81 12.75 10.8 10.76 8.82 8.79 9.58 8.03 11.55 10.01 13.53 8.03 14.28 8.79 12.31 10.76 14.3 12.75" fill="#fff" stroke-width="0"/><path d="M11.53,5.5l-4.46,2.59v5.34l.73.41h.01l3.72,2.16,4.47-2.58v-5.33l-4.47-2.59ZM13.54,13.51l-1.99-1.99-1.99,1.99-.75-.76,1.99-1.99-1.98-1.97.76-.76,1.97,1.98,1.98-1.98.75.76-1.97,1.97,1.99,1.99-.76.76Z" fill="#f1554c" stroke-width="0"/><polygon points="14.3 12.75 13.54 13.51 11.55 11.52 9.56 13.51 8.81 12.75 10.8 10.76 8.82 8.79 9.58 8.03 11.55 10.01 13.53 8.03 14.28 8.79 12.31 10.76 14.3 12.75" fill="#fff" stroke-width="0"/><polygon points="14.3 12.75 13.54 13.51 11.55 11.52 9.56 13.51 8.81 12.75 10.8 10.76 8.82 8.79 9.58 8.03 11.55 10.01 13.53 8.03 14.28 8.79 12.31 10.76 14.3 12.75" fill="#fff" stroke-width="0"/></svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

@@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><polygon points="5.39 10.21 5.98 9.87 5.98 7.41 8.1 6.19 8.1 5.52 7.51 5.18 5.38 6.41 3.28 5.19 2.69 5.53 2.69 6.21 4.81 7.43 4.81 9.87 5.39 10.21" fill="#e2baff" stroke-width="0"/><polygon points="10.79 3.11 5.4 0 5.4 0 5.4 0 0 3.11 0 4.47 5.4 1.36 10.79 4.47 10.79 3.11" fill="#e2baff" stroke-width="0"/><path d="M5.39,12.65L0,9.53v1.36l5.38,3.11,1.69-.98v-1.35l-1.69.98Z" fill="#e2baff" stroke-width="0"/><path d="M11.53,5.5l-4.45,2.59v5.34l.73.4h.01s3.71,2.17,3.71,2.17l4.47-2.58v-5.33l-4.47-2.59ZM12.06,13.96h-1.07v-4.45h1.07v4.45ZM11.52,8.92c-.37,0-.68-.3-.68-.68s.31-.69.68-.69c.39,0,.7.31.7.69s-.31.68-.7.68Z" fill="#239eb1" stroke-width="0"/><path d="M11.52,7.55c-.37,0-.68.31-.68.69s.31.68.68.68c.39,0,.7-.3.7-.68s-.31-.69-.7-.69ZM10.99,9.51v4.45h1.07v-4.45h-1.07Z" fill="#fff" stroke-width="0"/><path d="M11.53,5.5l-4.45,2.59v5.34l.73.4h.01s3.71,2.17,3.71,2.17l4.47-2.58v-5.33l-4.47-2.59ZM12.06,13.96h-1.07v-4.45h1.07v4.45ZM11.52,8.92c-.37,0-.68-.3-.68-.68s.31-.69.68-.69c.39,0,.7.31.7.69s-.31.68-.7.68Z" fill="#239eb1" stroke-width="0"/><path d="M11.52,7.55c-.37,0-.68.31-.68.69s.31.68.68.68c.39,0,.7-.3.7-.68s-.31-.69-.7-.69ZM10.99,9.51v4.45h1.07v-4.45h-1.07Z" fill="#fff" stroke-width="0"/></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

@@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><polygon points="7.995,11.21 8.585,10.87 8.585,8.41 10.694,7.19 10.694,6.51 10.114,6.17 7.985,7.4 5.885,6.19 5.295,6.53 5.295,7.21 7.415,8.43 7.415,10.87" fill="#e2baff" stroke-width="0"/><polygon points="13.395,4.11 7.995,1 7.995,1 7.995,1 2.605,4.11 2.605,5.47 7.995,2.36 13.395,5.47" fill="#e2baff" stroke-width="0"/><polygon points="13.395,10.53 7.995,13.641 2.605,10.53 2.605,11.891 7.995,15 7.995,15 7.995,15 13.395,11.891" fill="#e2baff" stroke-width="0"/></svg>

After

Width:  |  Height:  |  Size: 598 B

@@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><polygon points="5.39 10.21 5.98 9.87 5.98 7.41 8.09 6.19 8.09 5.52 7.5 5.18 5.38 6.41 3.28 5.19 2.69 5.53 2.69 6.21 4.81 7.43 4.81 9.87 5.39 10.21" fill="#e2baff" stroke-width="0"/><polygon points="10.78 3.11 5.39 0 5.39 0 5.39 0 0 3.11 0 4.47 5.39 1.36 10.78 4.47 10.78 3.11" fill="#e2baff" stroke-width="0"/><path d="M5.39,12.65L0,9.53v1.36l5.39,3.11,1.7-.98v-1.37l-1.7,1Z" fill="#e2baff" stroke-width="0"/><path d="M11.54,5.5l-4.45,2.59v5.33l.72.41h.02s3.71,2.17,3.71,2.17l4.46-2.58v-5.33l-4.46-2.59ZM9.68,11.52h-1.52v-1.53h1.52v1.53ZM12.28,11.52h-1.53v-1.53h1.53v1.53ZM14.86,11.52h-1.52v-1.53h1.52v1.53Z" fill="#20434f" stroke-width="0"/><path d="M8.16,9.99v1.53h1.52v-1.53h-1.52ZM10.75,9.99v1.53h1.53v-1.53h-1.53ZM13.34,9.99v1.53h1.52v-1.53h-1.52Z" fill="#fff" fill-rule="evenodd" stroke-width="0"/><path d="M11.54,5.5l-4.45,2.59v5.33l.72.41h.02s3.71,2.17,3.71,2.17l4.46-2.58v-5.33l-4.46-2.59ZM9.68,11.52h-1.52v-1.53h1.52v1.53ZM12.28,11.52h-1.53v-1.53h1.53v1.53ZM14.86,11.52h-1.52v-1.53h1.52v1.53Z" fill="#20434f" stroke-width="0"/><path d="M8.16,9.99v1.53h1.52v-1.53h-1.52ZM10.75,9.99v1.53h1.53v-1.53h-1.53ZM13.34,9.99v1.53h1.52v-1.53h-1.52Z" fill="#fff" fill-rule="evenodd" stroke-width="0"/></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

@@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><polygon points="5.4 10.21 5.98 9.87 5.98 7.41 8.1 6.19 8.1 5.52 7.51 5.18 5.38 6.41 3.28 5.19 2.7 5.53 2.7 6.21 4.81 7.43 4.81 9.87 5.4 10.21" fill="#e2baff" stroke-width="0"/><polygon points="10.79 3.11 5.4 0 5.4 0 5.4 0 0 3.11 0 4.47 5.4 1.36 10.79 4.47 10.79 3.11" fill="#e2baff" stroke-width="0"/><path d="M5.39,12.65L0,9.53v1.36l5.39,3.11,1.7-.98v-1.37l-1.7,1Z" fill="#e2baff" stroke-width="0"/><path d="M11.54,5.5l-4.45,2.59v5.23l.72.51h.02s3.71,2.17,3.71,2.17l4.46-2.58v-5.33l-4.46-2.59ZM11.12,13.04h-1.16v-4.57h1.16v4.57ZM13.13,13.04h-1.16v-4.57h1.16v4.57Z" fill="#ff9300" stroke-width="0"/><rect x="9.96" y="8.47" width="1.16" height="4.57" fill="#fff" stroke-width="0"/><rect x="11.97" y="8.47" width="1.16" height="4.57" fill="#fff" stroke-width="0"/><path d="M11.54,5.5l-4.45,2.59v5.23l.72.51h.02s3.71,2.17,3.71,2.17l4.46-2.58v-5.33l-4.46-2.59ZM11.12,13.04h-1.16v-4.57h1.16v4.57ZM13.13,13.04h-1.16v-4.57h1.16v4.57Z" fill="#ff9300" stroke-width="0"/><rect x="9.96" y="8.47" width="1.16" height="4.57" fill="#fff" stroke-width="0"/><rect x="11.97" y="8.47" width="1.16" height="4.57" fill="#fff" stroke-width="0"/></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

@@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><polygon points="5.4 10.22 5.99 9.88 5.99 7.42 8.1 6.2 8.1 5.52 7.51 5.18 5.38 6.41 3.28 5.2 2.7 5.54 2.7 6.22 4.81 7.44 4.81 9.88 5.4 10.22" fill="#e2baff" stroke-width="0"/><polygon points="10.8 3.12 5.4 0 5.4 0 5.4 0 0 3.12 0 4.48 5.4 1.36 10.8 4.48 10.8 3.12" fill="#e2baff" stroke-width="0"/><path d="M5.42,12.65L.02,9.52v1.37l5.4,3.11,1.68-.97v-1.35l-1.68.97Z" fill="#e2baff" stroke-width="0"/><path d="M11.56,5.5l-4.46,2.59v5.32l.72.42v.02h.02l3.72,2.15,4.44-2.58v-5.33l-4.44-2.59ZM14.84,11.67c-.02.11-.05.2-.09.3-.14.38-.35.71-.62,1.02l-.21.2c-.58.56-1.35.9-2.22.9s-1.64-.34-2.2-.88c-.22-.18-.38-.37-.51-.6l-.59.74-.18-1.87.28-.04.72-.13.86-.16h.02l-.64.81h0c.11.2.23.38.39.54.06.09.16.17.24.24.44.37.99.6,1.61.6s1.2-.24,1.64-.62c.3-.27.56-.6.7-1l.83-.15s0,.07-.03.1ZM14.89,10.11l-.71.12-.86.16h-.02l.63-.8v-.02c-.1-.19-.23-.37-.38-.53-.06-.09-.16-.17-.24-.24-.44-.37-1-.6-1.61-.6s-1.2.24-1.64.63c-.31.26-.57.6-.71.99l-.82.15s.01-.07.02-.1c.02-.1.06-.19.09-.3.15-.38.35-.71.62-1.02l.22-.2c.58-.55,1.35-.89,2.22-.89s1.63.34,2.2.87c.21.18.37.37.51.6l.59-.74.18,1.87-.29.05Z" fill="#239eb1" stroke-width="0"/><path d="M15.18,10.06l-.29.05-.71.12-.86.16h-.02l.63-.8v-.02c-.1-.19-.23-.37-.38-.53-.06-.09-.16-.17-.24-.24-.44-.37-1-.6-1.61-.6s-1.2.24-1.64.63c-.31.26-.57.6-.71.99l-.82.15s.01-.07.02-.1c.02-.1.06-.19.09-.3.15-.38.35-.71.62-1.02l.22-.2c.58-.55,1.35-.89,2.22-.89s1.63.34,2.2.87c.21.18.37.37.51.6l.59-.74.18,1.87Z" fill="#fff" stroke-width="0"/><path d="M14.87,11.57s0,.07-.03.1c-.02.11-.05.2-.09.3-.14.38-.35.71-.62,1.02l-.21.2c-.58.56-1.35.9-2.22.9s-1.64-.34-2.2-.88c-.22-.18-.38-.37-.51-.6l-.59.74-.18-1.87.28-.04.72-.13.86-.16h.02l-.64.81h0c.11.2.23.38.39.54.06.09.16.17.24.24.44.37.99.6,1.61.6s1.2-.24,1.64-.62c.3-.27.56-.6.7-1l.83-.15Z" fill="#fff" stroke-width="0"/><path d="M11.56,5.5l-4.46,2.59v5.32l.72.42v.02h.02l3.72,2.15,4.44-2.58v-5.33l-4.44-2.59ZM14.84,11.67c-.02.11-.05.2-.09.3-.14.38-.35.71-.62,1.02l-.21.2c-.58.56-1.35.9-2.22.9s-1.64-.34-2.2-.88c-.22-.18-.38-.37-.51-.6l-.59.74-.18-1.87.28-.04.72-.13.86-.16h.02l-.64.81h0c.11.2.23.38.39.54.06.09.16.17.24.24.44.37.99.6,1.61.6s1.2-.24,1.64-.62c.3-.27.56-.6.7-1l.83-.15s0,.07-.03.1ZM14.89,10.11l-.71.12-.86.16h-.02l.63-.8v-.02c-.1-.19-.23-.37-.38-.53-.06-.09-.16-.17-.24-.24-.44-.37-1-.6-1.61-.6s-1.2.24-1.64.63c-.31.26-.57.6-.71.99l-.82.15s.01-.07.02-.1c.02-.1.06-.19.09-.3.15-.38.35-.71.62-1.02l.22-.2c.58-.55,1.35-.89,2.22-.89s1.63.34,2.2.87c.21.18.37.37.51.6l.59-.74.18,1.87-.29.05Z" fill="#239eb1" stroke-width="0"/><path d="M15.18,10.06l-.29.05-.71.12-.86.16h-.02l.63-.8v-.02c-.1-.19-.23-.37-.38-.53-.06-.09-.16-.17-.24-.24-.44-.37-1-.6-1.61-.6s-1.2.24-1.64.63c-.31.26-.57.6-.71.99l-.82.15s.01-.07.02-.1c.02-.1.06-.19.09-.3.15-.38.35-.71.62-1.02l.22-.2c.58-.55,1.35-.89,2.22-.89s1.63.34,2.2.87c.21.18.37.37.51.6l.59-.74.18,1.87Z" fill="#fff" stroke-width="0"/><path d="M14.87,11.57s0,.07-.03.1c-.02.11-.05.2-.09.3-.14.38-.35.71-.62,1.02l-.21.2c-.58.56-1.35.9-2.22.9s-1.64-.34-2.2-.88c-.22-.18-.38-.37-.51-.6l-.59.74-.18-1.87.28-.04.72-.13.86-.16h.02l-.64.81h0c.11.2.23.38.39.54.06.09.16.17.24.24.44.37.99.6,1.61.6s1.2-.24,1.64-.62c.3-.27.56-.6.7-1l.83-.15Z" fill="#fff" stroke-width="0"/></svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

@@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><polygon points="5.39 10.21 5.98 9.87 5.98 7.41 8.1 6.19 8.1 5.52 7.51 5.18 5.38 6.41 3.28 5.19 2.69 5.53 2.69 6.21 4.81 7.43 4.81 9.87 5.39 10.21" fill="#20434f" stroke-width="0"/><polygon points="10.79 3.11 5.39 0 5.39 0 5.39 0 0 3.11 0 4.47 5.39 1.36 10.79 4.47 10.79 3.11" fill="#20434f" stroke-width="0"/><path d="M5.4,12.65L0,9.53v1.36l5.4,3.11,1.67-.96v-1.37l-1.67.98Z" fill="#20434f" stroke-width="0"/><path d="M11.53,5.5l-4.46,2.59v5.34l.73.41h.01l3.72,2.16,4.47-2.58v-5.33l-4.47-2.59ZM13.54,13.51l-1.99-1.99-1.99,1.99-.75-.76,1.99-1.99-1.98-1.97.76-.76,1.97,1.98,1.98-1.98.75.76-1.97,1.97,1.99,1.99-.76.76Z" fill="#f1554c" stroke-width="0"/><polygon points="14.3 12.75 13.54 13.51 11.55 11.52 9.56 13.51 8.81 12.75 10.8 10.76 8.82 8.79 9.58 8.03 11.55 10.01 13.53 8.03 14.28 8.79 12.31 10.76 14.3 12.75" fill="#fff" stroke-width="0"/><polygon points="14.3 12.75 13.54 13.51 11.55 11.52 9.56 13.51 8.81 12.75 10.8 10.76 8.82 8.79 9.58 8.03 11.55 10.01 13.53 8.03 14.28 8.79 12.31 10.76 14.3 12.75" fill="#fff" stroke-width="0"/></svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

@@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><polygon points="5.39 10.21 5.98 9.87 5.98 7.41 8.1 6.19 8.1 5.52 7.51 5.18 5.38 6.41 3.28 5.19 2.69 5.53 2.69 6.21 4.81 7.43 4.81 9.87 5.39 10.21" fill="#20434f" stroke-width="0"/><polygon points="10.79 3.11 5.4 0 5.4 0 5.4 0 0 3.11 0 4.47 5.4 1.36 10.79 4.47 10.79 3.11" fill="#20434f" stroke-width="0"/><path d="M5.39,12.65L0,9.53v1.36l5.38,3.11,1.69-.98v-1.35l-1.69.98Z" fill="#20434f" stroke-width="0"/><path d="M11.53,5.5l-4.45,2.59v5.34l.73.4h.01s3.71,2.17,3.71,2.17l4.47-2.58v-5.33l-4.47-2.59ZM12.06,13.96h-1.07v-4.45h1.07v4.45ZM11.52,8.92c-.37,0-.68-.3-.68-.68s.31-.69.68-.69c.39,0,.7.31.7.69s-.31.68-.7.68Z" fill="#239eb1" stroke-width="0"/><path d="M11.52,7.55c-.37,0-.68.31-.68.69s.31.68.68.68c.39,0,.7-.3.7-.68s-.31-.69-.7-.69ZM10.99,9.51v4.45h1.07v-4.45h-1.07Z" fill="#fff" stroke-width="0"/></svg>

After

Width:  |  Height:  |  Size: 940 B

@@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><polygon points="7.995,11.21 8.585,10.87 8.585,8.41 10.694,7.19 10.694,6.51 10.114,6.17 7.985,7.4 5.885,6.19 5.295,6.53 5.295,7.21 7.415,8.43 7.415,10.87" fill="#20434f" stroke-width="0"/><polygon points="13.395,4.11 7.995,1 7.995,1 7.995,1 2.605,4.11 2.605,5.47 7.995,2.36 13.395,5.47" fill="#20434f" stroke-width="0"/><polygon points="13.395,10.53 7.995,13.641 2.605,10.53 2.605,11.891 7.995,15 7.995,15 7.995,15 13.395,11.891" fill="#20434f" stroke-width="0"/></svg>

After

Width:  |  Height:  |  Size: 598 B

@@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><polygon points="5.39 10.21 5.98 9.87 5.98 7.41 8.09 6.19 8.09 5.52 7.5 5.18 5.38 6.4 3.28 5.19 2.69 5.53 2.69 6.21 4.8 7.43 4.8 9.87 5.39 10.21" fill="#20434f" stroke-width="0"/><polygon points="10.78 3.11 5.39 0 5.39 0 5.39 0 0 3.11 0 4.47 5.39 1.36 10.78 4.47 10.78 3.11" fill="#20434f" stroke-width="0"/><path d="M5.39,12.65L0,9.53v1.36l5.39,3.11,1.7-.98v-1.37l-1.7,1Z" fill="#20434f" stroke-width="0"/><path d="M11.54,5.5l-4.45,2.59v5.33l.72.41h.02s3.71,2.17,3.71,2.17l4.46-2.58v-5.33l-4.46-2.59ZM9.68,11.52h-1.52v-1.53h1.52v1.53ZM12.28,11.52h-1.53v-1.53h1.53v1.53ZM14.86,11.52h-1.52v-1.53h1.52v1.53Z" fill="#20434f" stroke-width="0"/><path d="M8.16,9.99v1.53h1.52v-1.53h-1.52ZM10.75,9.99v1.53h1.53v-1.53h-1.53ZM13.34,9.99v1.53h1.52v-1.53h-1.52Z" fill="#fff" fill-rule="evenodd" stroke-width="0"/></svg>

After

Width:  |  Height:  |  Size: 936 B

@@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><polygon points="5.4 10.21 5.98 9.87 5.98 7.41 8.1 6.19 8.1 5.52 7.51 5.18 5.38 6.41 3.28 5.19 2.7 5.53 2.7 6.21 4.81 7.43 4.81 9.87 5.4 10.21" fill="#20434f" stroke-width="0"/><polygon points="10.79 3.11 5.4 0 5.4 0 5.4 0 0 3.11 0 4.47 5.4 1.36 10.79 4.47 10.79 3.11" fill="#20434f" stroke-width="0"/><path d="M5.39,12.65L0,9.53v1.36l5.39,3.11,1.7-.98v-1.37l-1.7,1Z" fill="#20434f" stroke-width="0"/><path d="M11.54,5.5l-4.45,2.59v5.23l.72.51h.02s3.71,2.17,3.71,2.17l4.46-2.58v-5.33l-4.46-2.59ZM11.12,13.04h-1.16v-4.57h1.16v4.57ZM13.13,13.04h-1.16v-4.57h1.16v4.57Z" fill="#ff9300" stroke-width="0"/><rect x="9.96" y="8.47" width="1.16" height="4.57" fill="#fff" stroke-width="0"/><rect x="11.97" y="8.47" width="1.16" height="4.57" fill="#fff" stroke-width="0"/></svg>

After

Width:  |  Height:  |  Size: 897 B

@@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M11.56,5.5l-4.46,2.59v5.32l.72.42v.02h.02l3.72,2.15,4.44-2.58v-5.33l-4.44-2.59ZM14.84,11.67c-.02.11-.05.2-.09.3-.14.38-.35.71-.62,1.02l-.21.2c-.58.56-1.35.9-2.22.9s-1.64-.34-2.2-.88c-.22-.18-.38-.37-.51-.6l-.59.74-.18-1.87.28-.04.72-.13.86-.16h.02l-.64.81h0c.11.2.23.38.39.54.06.09.16.17.24.24.44.37.99.6,1.61.6s1.2-.24,1.64-.62c.3-.27.56-.6.7-1l.83-.15s0,.07-.03.1ZM14.89,10.11l-.71.12-.86.16h-.02l.63-.8v-.02c-.1-.19-.23-.37-.38-.53-.06-.09-.16-.17-.24-.24-.44-.37-1-.6-1.61-.6s-1.2.24-1.64.63c-.31.26-.57.6-.71.99l-.82.15s.01-.07.02-.1c.02-.1.06-.19.09-.3.15-.38.35-.71.62-1.02l.22-.2c.58-.55,1.35-.89,2.22-.89s1.63.34,2.2.87c.21.18.37.37.51.6l.59-.74.18,1.87-.29.05Z" fill="#239eb1" stroke-width="0"/><path d="M15.18,10.06l-.29.05-.71.12-.86.16h-.02l.63-.8v-.02c-.1-.19-.23-.37-.38-.53-.06-.09-.16-.17-.24-.24-.44-.37-1-.6-1.61-.6s-1.2.24-1.64.63c-.31.26-.57.6-.71.99l-.82.15s.01-.07.02-.1c.02-.1.06-.19.09-.3.15-.38.35-.71.62-1.02l.22-.2c.58-.55,1.35-.89,2.22-.89s1.63.34,2.2.87c.21.18.37.37.51.6l.59-.74.18,1.87Z" fill="#fff" stroke-width="0"/><path d="M14.87,11.57s0,.07-.03.1c-.02.11-.05.2-.09.3-.14.38-.35.71-.62,1.02l-.21.2c-.58.56-1.35.9-2.22.9s-1.64-.34-2.2-.88c-.22-.18-.38-.37-.51-.6l-.59.74-.18-1.87.28-.04.72-.13.86-.16h.02l-.64.81h0c.11.2.23.38.39.54.06.09.16.17.24.24.44.37.99.6,1.61.6s1.2-.24,1.64-.62c.3-.27.56-.6.7-1l.83-.15Z" fill="#fff" stroke-width="0"/><polygon points="5.4 10.22 5.99 9.88 5.99 7.42 8.1 6.2 8.1 5.52 7.51 5.18 5.38 6.41 3.28 5.2 2.7 5.54 2.7 6.22 4.81 7.44 4.81 9.88 5.4 10.22" fill="#20434f" stroke-width="0"/><polygon points="10.8 3.12 5.4 0 5.4 0 5.4 0 0 3.12 0 4.48 5.4 1.36 10.8 4.48 10.8 3.12" fill="#20434f" stroke-width="0"/><path d="M5.42,12.65L.02,9.52v1.37l5.4,3.11,1.68-.97v-1.35l-1.68.97Z" fill="#20434f" stroke-width="0"/></svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

@@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><polygon points="5.4 10.21 5.98 9.87 5.98 7.41 8.1 6.19 8.1 5.52 7.51 5.18 5.38 6.4 3.28 5.19 2.7 5.53 2.7 6.21 4.81 7.43 4.81 9.87 5.4 10.21" fill="#000" stroke-width="0"/><polygon points="10.79 3.11 5.4 0 5.4 0 5.4 0 0 3.11 0 4.47 5.4 1.36 10.79 4.47 10.79 3.11" fill="#000" stroke-width="0"/><path d="M11.53,5.5l-4.46,2.59v3.58l-1.67.98L0,9.53v1.36l5.4,3.11,1.67-.96v.39l.73.41h.01l3.72,2.16,4.47-2.58v-5.33l-4.47-2.59ZM13.54,13.51l-1.99-1.99-1.99,1.99-.75-.76,1.99-1.99-1.98-1.97.76-.76,1.97,1.98,1.98-1.98.75.76-1.97,1.97,1.99,1.99-.76.76Z" fill="#000" stroke-width="0"/></svg>

After

Width:  |  Height:  |  Size: 710 B

@@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><polygon points="5.39 10.21 5.98 9.87 5.98 7.41 8.1 6.19 8.1 5.52 7.51 5.18 5.38 6.4 3.28 5.19 2.69 5.53 2.69 6.21 4.81 7.43 4.81 9.87 5.39 10.21" fill="#000" stroke-width="0"/><polygon points="10.79 3.11 5.39 0 5.39 0 5.39 0 0 3.11 0 4.47 5.39 1.36 10.79 4.47 10.79 3.11" fill="#000" stroke-width="0"/><path d="M11.53,5.5l-4.45,2.59v3.58l-1.69.98L0,9.53v1.36l5.38,3.11,1.69-.98v.41l.73.4h.01s3.71,2.17,3.71,2.17l4.47-2.58v-5.33l-4.47-2.59ZM12.06,13.96h-1.07v-4.45h1.07v4.45ZM11.52,8.92c-.37,0-.68-.3-.68-.68s.31-.69.68-.69c.39,0,.7.31.7.69s-.31.68-.7.68Z" fill="#000" stroke-width="0"/></svg>

After

Width:  |  Height:  |  Size: 721 B

@@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><polygon points="7.995,11.21 8.585,10.87 8.585,8.41 10.694,7.19 10.694,6.51 10.114,6.17 7.985,7.4 5.885,6.19 5.295,6.53 5.295,7.21 7.415,8.43 7.415,10.87" fill="#000" stroke-width="0"/><polygon points="13.395,4.11 7.995,1 7.995,1 7.995,1 2.605,4.11 2.605,5.47 7.995,2.36 13.395,5.47" fill="#000" stroke-width="0"/><polygon points="13.395,10.53 7.995,13.641 2.605,10.53 2.605,11.891 7.995,15 7.995,15 7.995,15 13.395,11.891" fill="#000" stroke-width="0"/></svg>

After

Width:  |  Height:  |  Size: 589 B

@@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><polygon points="5.39 10.21 5.98 9.87 5.98 7.41 8.09 6.19 8.09 5.52 7.5 5.18 5.38 6.4 3.28 5.19 2.69 5.53 2.69 6.21 4.8 7.43 4.8 9.87 5.39 10.21" fill="#000" stroke-width="0"/><polygon points="10.78 3.11 5.39 0 5.39 0 5.39 0 0 3.11 0 4.47 5.39 1.36 10.78 4.47 10.78 3.11" fill="#000" stroke-width="0"/><path d="M11.54,5.5l-4.45,2.59v3.56l-1.7,1L0,9.53v1.36l5.39,3.11,1.7-.98v.4l.72.41h.02s3.71,2.17,3.71,2.17l4.46-2.58v-5.33l-4.46-2.59ZM9.68,11.52h-1.52v-1.53h1.52v1.53ZM12.28,11.52h-1.53v-1.53h1.53v1.53ZM14.86,11.52h-1.52v-1.53h1.52v1.53Z" fill="#000" stroke-width="0"/></svg>

After

Width:  |  Height:  |  Size: 706 B

@@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><polygon points="5.4 10.21 5.98 9.87 5.98 7.41 8.1 6.19 8.1 5.51 7.51 5.18 5.38 6.4 3.28 5.19 2.7 5.53 2.7 6.21 4.81 7.43 4.81 9.87 5.4 10.21" fill="#000" stroke-width="0"/><polygon points="10.79 3.11 5.4 0 5.4 0 5.4 0 0 3.11 0 4.47 5.4 1.36 10.79 4.47 10.79 3.11" fill="#000" stroke-width="0"/><path d="M11.54,5.5l-4.45,2.59v3.56l-1.7,1L0,9.53v1.36l5.39,3.11,1.7-.98v.3l.72.51h.02s3.71,2.17,3.71,2.17l4.46-2.58v-5.33l-4.46-2.59ZM11.12,13.04h-1.16v-4.57h1.16v4.57ZM13.13,13.04h-1.16v-4.57h1.16v4.57Z" fill="#000" stroke-width="0"/></svg>

After

Width:  |  Height:  |  Size: 665 B

@@ -0,0 +1 @@
<?xml version="1.0" encoding="UTF-8"?><svg id="a" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><polygon points="5.4 10.22 5.98 9.88 5.98 7.42 8.1 6.2 8.1 5.52 7.51 5.18 5.38 6.41 3.28 5.2 2.69 5.54 2.69 6.22 4.81 7.44 4.81 9.88 5.4 10.22" fill="#000" stroke-width="0"/><polygon points="10.79 3.12 5.4 0 5.4 0 5.4 0 0 3.12 0 4.48 5.4 1.36 10.79 4.48 10.79 3.12" fill="#000" stroke-width="0"/><path d="M11.56,5.5l-4.46,2.59v3.59l-1.68.97L.02,9.52v1.37l5.4,3.11,1.68-.97v.38l.72.42v.02h.02l3.72,2.15,4.44-2.58v-5.33l-4.44-2.59ZM14.84,11.67c-.02.11-.05.2-.09.3-.14.38-.35.71-.62,1.02l-.21.2c-.58.56-1.35.9-2.22.9s-1.64-.34-2.2-.88c-.22-.18-.38-.37-.51-.6l-.59.74-.18-1.87.28-.04.72-.13.86-.16h.02l-.64.81h0c.11.2.23.38.39.54.06.09.16.17.24.24.44.37.99.6,1.61.6s1.2-.24,1.64-.62c.3-.27.56-.6.7-1l.83-.15s0,.07-.03.1ZM14.89,10.11l-.71.12-.86.16h-.02l.63-.8v-.02c-.1-.19-.23-.37-.38-.53-.06-.09-.16-.17-.24-.24-.44-.37-1-.6-1.61-.6s-1.2.24-1.64.63c-.31.26-.57.6-.71.99l-.82.15s.01-.07.02-.1c.02-.1.06-.19.09-.3.15-.38.35-.71.62-1.02l.22-.2c.58-.55,1.35-.89,2.22-.89s1.63.34,2.2.87c.21.18.37.37.51.6l.59-.74.18,1.87-.29.05Z" fill="#000" stroke-width="0"/></svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

+10
View File
@@ -0,0 +1,10 @@
import subprocess
from pathlib import Path
themeDir = Path(__file__).parent
for res in [16, 24, 32, 48, 64, 128, 256, 512, 1024]:
subprocess.run(["inkscape", themeDir / "universal/qsfera-icon.svg", "-w", str(res), "-h", str(res), "--export-filename", themeDir / f"colored/{res}-qsfera-icon.png"])
subprocess.run(["inkscape", themeDir / "universal/qsfera-icon-sidebar.svg", "-w", str(res), "-h", str(res), "--export-filename", themeDir / f"colored/{res}-qsfera-icon-sidebar.png"])
for res in [44, 150, 310]:
subprocess.run(["inkscape", themeDir / "universal/qsfera-icon.svg", "-w", str(res), "-h", str(res), "--export-filename", themeDir / f"colored/{res}-qsfera-icon-ms.png"])
@@ -0,0 +1,9 @@
<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 108 108">
<path fill="none" stroke="#000000" stroke-linecap="round" stroke-width="6" d="M45,28C60,18 82,22 91,40C100,58 91,79 73,87"/>
<path fill="none" stroke="#000000" stroke-linecap="round" stroke-width="2.5" d="M48,27C60,21 77,24 87,37"/>
<path fill="#000000" d="M25,29h15v31h-15z"/>
<path fill="#000000" d="M25,60h15v24h-15z"/>
<path fill="#000000" d="M42,54L63,31H82L56,60z"/>
<path fill="#000000" d="M42,61L56,48L84,84H65z"/>
<path fill="#000000" fill-opacity="0.45" d="M25,29h15v5h-15z"/>
</svg>

After

Width:  |  Height:  |  Size: 596 B

@@ -0,0 +1,20 @@
<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 108 108">
<defs>
<clipPath id="icon-mask" clipPathUnits="userSpaceOnUse">
<path d="M20.4,7.2h67.2C94.8,7.2 100.8,13.2 100.8,20.4v67.2C100.8,94.8 94.8,100.8 87.6,100.8H20.4C13.2,100.8 7.2,94.8 7.2,87.6V20.4C7.2,13.2 13.2,7.2 20.4,7.2z"/>
</clipPath>
</defs>
<g clip-path="url(#icon-mask)">
<path fill="#061D2B" d="M0,0h108v108h-108z"/>
<path fill="#0A2E42" fill-opacity="0.88" d="M0,0h108v108h-108z"/>
<path fill="#123E55" fill-opacity="0.72" d="M0,26C22,10 48,10 70,27C87,40 98,40 108,34L108,0L0,0z"/>
<path fill="#19B8C9" fill-opacity="0.18" d="M0,76C20,64 42,63 62,75C80,86 95,86 108,78L108,108L0,108z"/>
<path fill="none" stroke="#20D6E6" stroke-linecap="round" stroke-width="6" d="M45,28C60,18 82,22 91,40C100,58 91,79 73,87"/>
<path fill="none" stroke="#9AF8FF" stroke-linecap="round" stroke-width="2.5" d="M48,27C60,21 77,24 87,37"/>
<path fill="#21D1D6" d="M25,29h15v31h-15z"/>
<path fill="#F8FCFF" d="M25,60h15v24h-15z"/>
<path fill="#18BFD0" d="M42,54L63,31H82L56,60z"/>
<path fill="#F8FCFF" d="M42,61L56,48L84,84H65z"/>
<path fill="#9DF8FF" fill-opacity="0.45" d="M25,29h15v5h-15z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

@@ -0,0 +1,41 @@
# This file contains fixed global exclude patterns
*~
~$*
.~lock.*
~*.tmp
]*.~*
]Icon\r*
].DS_Store
].ds_store
._*
]Thumbs.db
.*.sw?
.*.*sw?
].TemporaryItems
].Trashes
].DocumentRevisions-V100
].Trash-*
.fseventd
.apdisk
.directory
*.part
*.filepart
*.crdownload
*.kate-swp
*.gnucash.tmp-*
.synkron.*
.sync.ffs_db
.symform
.symform-store
.fuse_hidden*
*.unison
.nfs*
My Saved Places.
@@ -0,0 +1,21 @@
<svg xmlns="http://www.w3.org/2000/svg" width="150" height="35" viewBox="0 0 150 35">
<defs>
<clipPath id="icon-mask" clipPathUnits="userSpaceOnUse">
<path d="M20.4,7.2h67.2C94.8,7.2 100.8,13.2 100.8,20.4v67.2C100.8,94.8 94.8,100.8 87.6,100.8H20.4C13.2,100.8 7.2,94.8 7.2,87.6V20.4C7.2,13.2 13.2,7.2 20.4,7.2z"/>
</clipPath>
</defs>
<g transform="scale(0.324074)" clip-path="url(#icon-mask)">
<path fill="#061D2B" d="M0,0h108v108h-108z"/>
<path fill="#0A2E42" fill-opacity="0.88" d="M0,0h108v108h-108z"/>
<path fill="#123E55" fill-opacity="0.72" d="M0,26C22,10 48,10 70,27C87,40 98,40 108,34L108,0L0,0z"/>
<path fill="#19B8C9" fill-opacity="0.18" d="M0,76C20,64 42,63 62,75C80,86 95,86 108,78L108,108L0,108z"/>
<path fill="none" stroke="#20D6E6" stroke-linecap="round" stroke-width="6" d="M45,28C60,18 82,22 91,40C100,58 91,79 73,87"/>
<path fill="none" stroke="#9AF8FF" stroke-linecap="round" stroke-width="2.5" d="M48,27C60,21 77,24 87,37"/>
<path fill="#21D1D6" d="M25,29h15v31h-15z"/>
<path fill="#F8FCFF" d="M25,60h15v24h-15z"/>
<path fill="#18BFD0" d="M42,54L63,31H82L56,60z"/>
<path fill="#F8FCFF" d="M42,61L56,48L84,84H65z"/>
<path fill="#9DF8FF" fill-opacity="0.45" d="M25,29h15v5h-15z"/>
</g>
<text x="43" y="24" fill="#F8FCFF" font-family="Segoe UI, Arial, sans-serif" font-size="18" font-weight="700">КуСфера</text>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

+36
View File
@@ -0,0 +1,36 @@
/*
* Copyright (C) by Hannah von Reth <hannah.vonreth@owncloud.com>
*
* 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 2 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.
*/
#include "themewatcher.h"
#include <QCoreApplication>
#include <QEvent>
namespace OCC {
namespace Resources {
ThemeWatcher::ThemeWatcher(QObject *parent)
: QObject(parent)
{
qApp->installEventFilter(this);
}
bool ThemeWatcher::eventFilter(QObject *watched, QEvent *event)
{
if (event->type() == QEvent::ThemeChange) {
Q_EMIT themeChanged();
}
return QObject::eventFilter(watched, event);
}
} // Resources
} // OCC
+38
View File
@@ -0,0 +1,38 @@
/*
* Copyright (C) by Hannah von Reth <hannah.vonreth@owncloud.com>
*
* 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 2 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.
*/
#pragma once
#include "resources/qsferaresourceslib.h"
#include <QtWidgets/QWidget>
namespace OCC {
namespace Resources {
class QSFERA_RESOURCES_EXPORT ThemeWatcher : public QObject
{
Q_OBJECT
public:
ThemeWatcher(QObject *parent = nullptr);
Q_SIGNALS:
void themeChanged();
protected:
bool eventFilter(QObject *watched, QEvent *event) override;
};
} // Resources
} // OCC
+87
View File
@@ -0,0 +1,87 @@
/*
it turned out to be easier to apply styles as "locally" as possible, i.e., just apply where necessary
we use a dedicated widget as a container for the pages within the wizard window
styles will be inherited by all child widgets, so we'd have to guess the original values for all elements which we
do not want to style
the navigation/pagination part is located outside the content widget, so it won't be affected by this stylesheet
especially since we prefix all rules with #contentWidget
note that @\{...\} are variables replaced by our own code when loading the stylesheet
they represent theme-specific colors
*/
/*
unfortunately, if we want to change the background color altogether, we have to set it it on the top level element
and reset it to the original value where needed (some group boxes)
*/
#contentWidget
{
background-color: @{WIZARD_BACKGROUND_COLOR};
}
/* selectively set the font color for most labels and one group box title */
#contentWidget #welcomeTextLabel,
#contentWidget #serverUrlLabel,
#contentWidget #youreAllSetLabel,
#contentWidget #enterYourCredentialsLabel,
#contentWidget #enterYourUsernameLabel,
#contentWidget #urlLabel,
#contentWidget #usernameLabel,
#contentWidget #passwordLabel,
#contentWidget #topLabel,
#contentWidget #usernameLabel,
#contentWidget #passwordLabel,
#contentWidget #advancedConfigGroupBox::title,
#contentWidget #instancesListLabel
{
color: @{WIZARD_FONT_COLOR};
}
/*
the group box also has got a content widget, which we can easily hide from C++ when it is not checked
a side effect of this is that it makes setting the original background color a lot easier, since we do not have to
set the margins/paddings of the parent group box
*/
#contentWidget #advancedConfigGroupBoxContentWidget
{
/*
fortunately, we can just reuse the colors from the original theme using the QPalette macro
this is significantly better than having to set a specific color in some way
*/
background-color: palette(window);
}
#contentWidget #advancedConfigGroupBox
{
/*
the border would be hidden by the content widget anyway, and the content widget background color typically
provides sufficient contrast
*/
border: 0;
}
#contentWidget #advancedConfigGroupBox:checked {
/*
this value is combined with some suitable top margin on the layout in Qt Designer
(must be non-0, otherwise the stylesheet value does not have any effect)
*/
margin-top: 16px;
}
/* server URL page */
#contentWidget QLabel#welcomeTextLabel { font-size: 30px; }
#contentWidget QLabel#serverUrlLabel { font-size: 16px; }
/* credentials pages (common) */
#contentWidget QLabel#urlLabel { font-size: 16px; }
/* basic auth credentials page */
#contentWidget QLabel#enterYourCredentialsLabel { font-size: 16px; }
/* OAuth2 credentials page */
#contentWidget QLabel#pleaseLogIntoLabel { font-size: 16px; }
/* account configured page */
#contentWidget QLabel#youreAllSetLabel { font-size: 30px; }