Initial commit

dockerfile
tobtoht 3 years ago
commit 1be50e306a

2
.gitignore vendored

@ -0,0 +1,2 @@
cmake-build-debug/
.idea/

@ -0,0 +1,221 @@
cmake_minimum_required(VERSION 3.13)
project(moneroservice)
message(STATUS "Initiating compile using CMake ${CMAKE_VERSION}")
set(THREADS_PREFER_PTHREAD_FLAG ON)
set(VERSION_MAJOR "0")
set(VERSION_MINOR "1")
set(VERSION_REVISION "0")
set(VERSION "beta-3")
list(INSERT CMAKE_MODULE_PATH 0 "${CMAKE_SOURCE_DIR}/cmake")
include(CheckCCompilerFlag)
include(CheckCXXCompilerFlag)
include(CheckLinkerFlag)
include(FetchContent)
include(FindCcache)
include(CheckIncludeFile)
include(CheckSymbolExists)
if(DEBUG)
set(CMAKE_VERBOSE_MAKEFILE ON)
endif()
set(ARCH "x86-64")
set(BUILD_64 ON)
set(USE_SINGLE_BUILDDIR ON)
check_include_file(sys/prctl.h HAVE_SYS_PRCTL_H)
check_symbol_exists(prctl "sys/prctl.h" HAVE_PRCTL)
function (add_c_flag_if_supported flag var)
string(REPLACE "-" "_" supported ${flag}_c)
check_c_compiler_flag(${flag} ${supported})
if(${${supported}})
set(${var} "${${var}} ${flag}" PARENT_SCOPE)
endif()
endfunction()
function (add_cxx_flag_if_supported flag var)
string(REPLACE "-" "_" supported ${flag}_cxx)
check_cxx_compiler_flag(${flag} ${supported})
if(${${supported}})
set(${var} "${${var}} ${flag}" PARENT_SCOPE)
endif()
endfunction()
function (add_linker_flag_if_supported flag var)
string(REPLACE "-" "_" supported ${flag}_ld)
string(REPLACE "," "_" supported ${flag}_ld)
check_linker_flag(${flag} ${supported})
if(${${supported}})
set(${var} "${${var}} ${flag}" PARENT_SCOPE)
endif()
endfunction()
include(CMakePackageConfigHelpers)
if(UNIX AND NOT APPLE)
if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
# https://github.com/monero-project/monero-gui/issues/3142#issuecomment-705940446
set(CMAKE_SKIP_RPATH ON)
endif()
find_package(X11 REQUIRED)
message(STATUS "X11_FOUND = ${X11_FOUND}")
message(STATUS "X11_INCLUDE_DIR = ${X11_INCLUDE_DIR}")
message(STATUS "X11_LIBRARIES = ${X11_LIBRARIES}")
include_directories(${X11_INCLUDE_DIR})
link_directories(${X11_LIBRARIES})
if(STATIC)
find_library(XCB_LIBRARY xcb)
message(STATUS "Found xcb library: ${XCB_LIBRARY}")
endif()
endif()
if(MINGW)
string(REGEX MATCH "^[^/]:/[^/]*" msys2_install_path "${CMAKE_C_COMPILER}")
message(STATUS "MSYS location: ${msys2_install_path}")
set(CMAKE_INCLUDE_PATH "${msys2_install_path}/mingw${ARCH_WIDTH}/include")
# This is necessary because otherwise CMake will make Boost libraries -lfoo
# rather than a full path. Unfortunately, this makes the shared libraries get
# linked due to a bug in CMake which misses putting -static flags around the
# -lfoo arguments.
set(DEFLIB ${msys2_install_path}/mingw${ARCH_WIDTH}/lib)
list(REMOVE_ITEM CMAKE_C_IMPLICIT_LINK_DIRECTORIES ${DEFLIB})
list(REMOVE_ITEM CMAKE_CXX_IMPLICIT_LINK_DIRECTORIES ${DEFLIB})
endif()
if(MINGW)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wa,-mbig-obj")
set(EXTRA_LIBRARIES mswsock;ws2_32;iphlpapi;crypt32;bcrypt)
if(DEPENDS)
set(ICU_LIBRARIES iconv)
else()
set(ICU_LIBRARIES icuio icuin icuuc icudt icutu iconv)
endif()
elseif(APPLE)
set(EXTRA_LIBRARIES "-framework AppKit")
elseif(OPENBSD)
set(EXTRA_LIBRARIES "")
elseif(FREEBSD)
set(EXTRA_LIBRARIES execinfo)
elseif(DRAGONFLY)
find_library(COMPAT compat)
set(EXTRA_LIBRARIES execinfo ${COMPAT})
elseif(CMAKE_SYSTEM_NAME MATCHES "(SunOS|Solaris)")
set(EXTRA_LIBRARIES socket nsl resolv)
elseif(NOT MSVC AND NOT DEPENDS)
find_library(RT rt)
set(EXTRA_LIBRARIES ${RT})
endif()
list(APPEND EXTRA_LIBRARIES ${CMAKE_DL_LIBS})
if(APPLE)
include_directories(SYSTEM /usr/include/malloc)
if(POLICY CMP0042)
cmake_policy(SET CMP0042 NEW)
endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=x86-64 -fvisibility=default -std=c++11")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=default -DGTEST_HAS_TR1_TUPLE=0")
endif()
if (APPLE AND NOT IOS)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=x86-64 -fvisibility=default -std=c++11")
endif()
if(APPLE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=default -DGTEST_HAS_TR1_TUPLE=0")
endif()
# warnings
# @TODO: enable these 2 for migration to Qt 6
#add_c_flag_if_supported(-Werror C_SECURITY_FLAGS)
#add_cxx_flag_if_supported(-Werror CXX_SECURITY_FLAGS)
add_c_flag_if_supported(-Wformat C_SECURITY_FLAGS)
add_cxx_flag_if_supported(-Wformat CXX_SECURITY_FLAGS)
add_c_flag_if_supported(-Wformat-security C_SECURITY_FLAGS)
add_cxx_flag_if_supported(-Wformat-security CXX_SECURITY_FLAGS)
# -fstack-protector
if (NOT OPENBSD AND NOT (WIN32 AND (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_LESS 9.1)))
add_c_flag_if_supported(-fstack-protector C_SECURITY_FLAGS)
add_cxx_flag_if_supported(-fstack-protector CXX_SECURITY_FLAGS)
add_c_flag_if_supported(-fstack-protector-strong C_SECURITY_FLAGS)
add_cxx_flag_if_supported(-fstack-protector-strong CXX_SECURITY_FLAGS)
endif()
# New in GCC 8.2
if (NOT OPENBSD AND NOT (WIN32 AND (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_LESS 9.1)))
add_c_flag_if_supported(-fcf-protection=full C_SECURITY_FLAGS)
add_cxx_flag_if_supported(-fcf-protection=full CXX_SECURITY_FLAGS)
endif()
if (NOT WIN32 AND NOT OPENBSD)
add_c_flag_if_supported(-fstack-clash-protection C_SECURITY_FLAGS)
add_cxx_flag_if_supported(-fstack-clash-protection CXX_SECURITY_FLAGS)
endif()
# Removed in GCC 9.1 (or before ?), but still accepted, so spams the output
if (NOT (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 9.1))
add_c_flag_if_supported(-mmitigate-rop C_SECURITY_FLAGS)
add_cxx_flag_if_supported(-mmitigate-rop CXX_SECURITY_FLAGS)
endif()
# linker
if (APPLE)
add_linker_flag_if_supported(-Wl,-bind_at_load LD_SECURITY_FLAGS)
add_linker_flag_if_supported(-Wl,-dead_strip LD_SECURITY_FLAGS)
add_linker_flag_if_supported(-Wl,-dead_strip_dylibs LD_SECURITY_FLAGS)
endif()
if (NOT APPLE AND NOT (WIN32 AND CMAKE_C_COMPILER_ID STREQUAL "GNU"))
# Windows binaries die on startup with PIE when compiled with GCC
add_linker_flag_if_supported(-pie LD_SECURITY_FLAGS)
endif()
add_linker_flag_if_supported(-Wl,-z,relro LD_SECURITY_FLAGS)
add_linker_flag_if_supported(-Wl,-z,now LD_SECURITY_FLAGS)
add_linker_flag_if_supported(-Wl,-z,noexecstack noexecstack_SUPPORTED)
if (noexecstack_SUPPORTED)
set(LD_SECURITY_FLAGS "${LD_SECURITY_FLAGS} -Wl,-z,noexecstack")
endif()
add_linker_flag_if_supported(-Wl,-z,noexecheap noexecheap_SUPPORTED)
if (noexecheap_SUPPORTED)
set(LD_SECURITY_FLAGS "${LD_SECURITY_FLAGS} -Wl,-z,noexecheap")
endif()
# some windows linker bits
if (WIN32)
add_linker_flag_if_supported(-Wl,--dynamicbase LD_SECURITY_FLAGS)
add_linker_flag_if_supported(-Wl,--nxcompat LD_SECURITY_FLAGS)
add_linker_flag_if_supported(-Wl,--high-entropy-va LD_SECURITY_FLAGS)
endif()
if(STATIC)
add_linker_flag_if_supported(-static-libgcc STATIC_FLAGS)
add_linker_flag_if_supported(-static-libstdc++ STATIC_FLAGS)
if(MINGW)
add_linker_flag_if_supported(-static STATIC_FLAGS)
endif()
endif()
# With GCC 6.1.1 the compiled binary malfunctions due to aliasing. Until that
# is fixed in the code (Issue #847), force compiler to be conservative.
add_c_flag_if_supported(-fno-strict-aliasing C_SECURITY_FLAGS)
add_cxx_flag_if_supported(-fno-strict-aliasing CXX_SECURITY_FLAGS)
add_c_flag_if_supported(-fPIC C_SECURITY_FLAGS)
add_cxx_flag_if_supported(-fPIC CXX_SECURITY_FLAGS)
message(STATUS "Using C security hardening flags: ${C_SECURITY_FLAGS}")
message(STATUS "Using C++ security hardening flags: ${CXX_SECURITY_FLAGS}")
message(STATUS "Using linker security hardening flags: ${LD_SECURITY_FLAGS}")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c11 ${C_SECURITY_FLAGS}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 ${CXX_SECURITY_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${LD_SECURITY_FLAGS} ${STATIC_FLAGS}")
add_subdirectory(src)

@ -0,0 +1,14 @@
#ifdef __CLASSIC_C__
int main()
{
int ac;
char* av[];
#else
int main(int ac, char* av[])
{
#endif
if (ac > 1000) {
return *av[0];
}
return 0;
}

@ -0,0 +1,47 @@
include(CheckCCompilerFlag)
macro(CHECK_LINKER_FLAG flag VARIABLE)
if(NOT DEFINED "${VARIABLE}")
if(NOT CMAKE_REQUIRED_QUIET)
message(STATUS "Looking for ${flag} linker flag")
endif()
set(_cle_source ${CMAKE_SOURCE_DIR}/cmake/CheckLinkerFlag.c)
set(saved_CMAKE_C_FLAGS ${CMAKE_C_FLAGS})
set(CMAKE_C_FLAGS "${flag}")
try_compile(${VARIABLE}
${CMAKE_BINARY_DIR}
${_cle_source}
COMPILE_DEFINITIONS ${CMAKE_REQUIRED_DEFINITIONS} ${flag}
CMAKE_FLAGS
OUTPUT_VARIABLE OUTPUT)
unset(_cle_source)
set(CMAKE_C_FLAGS ${saved_CMAKE_C_FLAGS})
unset(saved_CMAKE_C_FLAGS)
if ("${OUTPUT}" MATCHES "warning.*ignored")
set(${VARIABLE} 0)
endif()
if(${VARIABLE})
if(NOT CMAKE_REQUIRED_QUIET)
message(STATUS "Looking for ${flag} linker flag - found")
endif()
set(${VARIABLE} 1 CACHE INTERNAL "Have linker flag ${flag}")
file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
"Determining if the ${flag} linker flag is supported "
"passed with the following output:\n"
"${OUTPUT}\n\n")
else()
if(NOT CMAKE_REQUIRED_QUIET)
message(STATUS "Looking for ${flag} linker flag - not found")
endif()
set(${VARIABLE} "" CACHE INTERNAL "Have linker flag ${flag}")
file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
"Determining if the ${flag} linker flag is supported "
"failed with the following output:\n"
"${OUTPUT}\n\n")
endif()
endif()
endmacro()

@ -0,0 +1,56 @@
# Copyright (c) 2014-2020, The Monero Project
#
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification, are
# permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this list of
# conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice, this list
# of conditions and the following disclaimer in the documentation and/or other
# materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its contributors may be
# used to endorse or promote products derived from this software without specific
# prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
# THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# - Try to find readline include dirs and libraries
#
# Automatically finds ccache build accelerator, if it's found in PATH.
#
# Usage of this module as follows:
#
# project(monero)
# include(FindCcache) # Include AFTER the project() macro to be able to reach the CMAKE_CXX_COMPILER variable
#
# Properties modified by this module:
#
# GLOBAL PROPERTY RULE_LAUNCH_COMPILE set to ccache, when ccache found
# GLOBAL PROPERTY RULE_LAUNCH_LINK set to ccache, when ccache found
find_program(CCACHE_FOUND ccache)
if (CCACHE_FOUND)
set(TEMP_CPP_FILE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/test-program.cpp")
file(WRITE "${TEMP_CPP_FILE}" "int main() { return 0; }")
execute_process(COMMAND "${CCACHE_FOUND}" "${CMAKE_CXX_COMPILER}" "${TEMP_CPP_FILE}" RESULT_VARIABLE RET)
if (${RET} EQUAL 0)
message("found usable ccache: ${CCACHE_FOUND}")
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_FOUND}")
set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK "${CCACHE_FOUND}")
else()
message("found ccache ${CCACHE_FOUND}, but is UNUSABLE! Return code: ${RET}")
endif()
else()
message("ccache NOT found!")
endif()

@ -0,0 +1,68 @@
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
# pthread
find_package(Threads REQUIRED)
find_package(Qt5 REQUIRED COMPONENTS Core Widgets Gui)
qt5_add_resources(RESOURCES assets.qrc)
# Compile source files (.h/.cpp)
file(GLOB SOURCE_FILES
"*.h"
"*.cpp"
"ui/BreezeStyleSheets/breeze.qrc"
"ui/qdarkstyle/style.qrc"
)
set(EXECUTABLE_FLAG)
add_executable(moneroservice ${EXECUTABLE_FLAG} main.cpp
${SOURCE_FILES}
${RESOURCES}
)
set_property(TARGET moneroservice PROPERTY RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
target_include_directories(moneroservice PUBLIC ${Qt5Gui_PRIVATE_INCLUDE_DIRS})
file(GLOB_RECURSE SRC_SOURCES *.cpp)
file(GLOB_RECURSE SRC_HEADERS *.h)
target_include_directories(moneroservice PUBLIC
${CMAKE_BINARY_DIR}/src/moneroservice_autogen/include
${CMAKE_SOURCE_DIR}/src
${CMAKE_CURRENT_SOURCE_DIR}
${X11_INCLUDE_DIR}
${Qt5Core_INCLUDE_DIRS}
${Qt5Widgets_INCLUDE_DIRS}
${Qt5Gui_INCLUDE_DIRS}
)
target_compile_definitions(moneroservice
PUBLIC
${Qt5Core_DEFINITIONS}
${Qt5Widgets_DEFINITIONS}
${Qt5Gui_DEFINITIONS}
)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}")
target_link_libraries(moneroservice
${CMAKE_DL_LIBS}
${EXTRA_LIBRARIES}
Qt5::Core
Qt5::Widgets
Qt5::Gui
${ICU_LIBRARIES}
Threads::Threads
)
if(X11_FOUND)
target_link_libraries(moneroservice ${X11_LIBRARIES})
endif()
install(TARGETS moneroservice
DESTINATION ${CMAKE_INSTALL_PREFIX}
)

@ -0,0 +1,61 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2021, The Monero Project.
#include "CommandLineEdit.h"
#include <QKeyEvent>
CommandLineEdit::CommandLineEdit(QWidget *parent) : QLineEdit(parent)
{
connect(this, &QLineEdit::returnPressed, this, &CommandLineEdit::updateHistory);
}
void CommandLineEdit::keyPressEvent(QKeyEvent *event) {
if (event->key() == Qt::Key_Up) {
if (m_historyIndex == m_history.size()) {
m_currentLine = this->text();
}
if (this->decreaseIndex()) {
this->setText(this->getCommand(m_historyIndex));
}
} else if (event->key() == Qt::Key_Down) {
if (this->increaseIndex()) {
this->setText(this->getCommand(m_historyIndex));
}
}
QLineEdit::keyPressEvent(event);
}
bool CommandLineEdit::decreaseIndex() {
if (m_historyIndex > 0 && m_history.size() >= m_historyIndex) {
m_historyIndex -= 1;
return true;
}
return false;
}
bool CommandLineEdit::increaseIndex() {
if (m_historyIndex < m_history.size()) {
m_historyIndex += 1;
return true;
}
return false;
}
QString CommandLineEdit::getCommand(int index) {
if (index < m_history.size()) {
return m_history[index];
} else {
return m_currentLine;
}
}
void CommandLineEdit::updateHistory() {
QString command = this->text();
if (m_history.isEmpty() || m_history.last() != command) {
m_history << command;
m_historyIndex = m_history.size();
}
this->setText("");
emit commandExecuted(command.split(" "));
}

@ -0,0 +1,33 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2021, The Monero Project.
#ifndef MONEROSERVICE_COMMANDLINEEDIT_H
#define MONEROSERVICE_COMMANDLINEEDIT_H
#include <QObject>
#include <QLineEdit>
class CommandLineEdit : public QLineEdit {
Q_OBJECT
public:
explicit CommandLineEdit(QWidget *parent = nullptr);
void keyPressEvent(QKeyEvent *event) override;
signals:
void commandExecuted(const QStringList &command);
private:
void updateHistory();
bool decreaseIndex();
bool increaseIndex();
QString getCommand(int index);
QString m_currentLine;
int m_historyIndex = 1;
QStringList m_history;
};
#endif //MONEROSERVICE_COMMANDLINEEDIT_H

@ -0,0 +1,118 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2020-2021, The Monero Project.
// Copyright (c) 2020 KeePassXC Team <team@keepassxc.org>
// Copyright (c) 2011 Felix Geyer <debfx@fobos.de>
#include "Config.h"
#include <QDir>
#include <QCoreApplication>
#define QS QStringLiteral
struct ConfigDirective
{
QString name;
QVariant defaultValue;
};
static const QHash<Config::ConfigKey, ConfigDirective> configStrings = {
{Config::network,{QS("network"), "mainnet"}},
{Config::pathToMonerod,{QS("pathToMonerod"), ""}},
{Config::pruneBlockchain,{QS("pruneBlockchain"), true}},
{Config::dataDir,{QS("dataDir"), ""}},
{Config::logLevel,{QS("logLevel"), 0}},
{Config::limitRateDown,{QS("limitRateDown"), 0}},
{Config::customStartupFlags,{QS("customStartupFlags"), ""}},
{Config::noZeroMQ,{QS("noZeroMQ"), true}},
{Config::RPCBindIP,{QS("RPCBindIP"), ""}},
{Config::RPCBindPort,{QS("RPCBindPort"), 0}},
{Config::P2PBindIP,{QS("P2PBindIP"), ""}},
{Config::P2PBindPort,{QS("P2PBindPort"), 0}},
};
QPointer<Config> Config::m_instance(nullptr);
QVariant Config::get(ConfigKey key)
{
auto cfg = configStrings[key];
auto defaultValue = configStrings[key].defaultValue;
return m_settings->value(cfg.name, defaultValue);
}
QString Config::getFileName()
{
return m_settings->fileName();
}
void Config::set(ConfigKey key, const QVariant& value)
{
if (get(key) == value) {
return;
}
auto cfg = configStrings[key];
m_settings->setValue(cfg.name, value);
this->sync();
emit changed(key);
}
/**
* Sync configuration with persistent storage.
*
* Usually, you don't need to call this method manually, but if you are writing
* configurations after an emitted \link QCoreApplication::aboutToQuit() signal,
* use it to guarantee your config values are persisted.
*/
void Config::sync()
{
m_settings->sync();
}
void Config::resetToDefaults()
{
m_settings->clear();
}
Config::Config(const QString& fileName, QObject* parent)
: QObject(parent)
{
init(fileName);
}
Config::Config(QObject* parent)
: QObject(parent)
{
QString configPath;
configPath = QDir::homePath();
configPath += "/.config/moneroservice/settings.json";
init(QDir::toNativeSeparators(configPath));
}
Config::~Config()
{
}
void Config::init(const QString& configFileName)
{
// const QSettings::Format jsonFormat = QSettings::registerFormat("json", Utils::readJsonFile, Utils::writeJsonFile);
// QSettings::setDefaultFormat(jsonFormat);
m_settings.reset(new QSettings());
connect(qApp, &QCoreApplication::aboutToQuit, this, &Config::sync);
}
Config* Config::instance()
{
if (!m_instance) {
m_instance = new Config(qApp);
}
return m_instance;
}

@ -0,0 +1,64 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2020-2021, The Monero Project.
// Copyright (c) 2020 KeePassXC Team <team@keepassxc.org>
// Copyright (c) 2011 Felix Geyer <debfx@fobos.de>
#ifndef MONEROSERVICE_SETTINGS_H
#define MONEROSERVICE_SETTINGS_H
#include <QObject>
#include <QSettings>
#include <QPointer>
class Config : public QObject
{
Q_OBJECT
public:
Q_DISABLE_COPY(Config)
enum ConfigKey
{
network,
pathToMonerod,
pruneBlockchain,
dataDir,
logLevel,
limitRateDown,
customStartupFlags,
noZeroMQ,
RPCBindIP,
RPCBindPort,
P2PBindIP,
P2PBindPort
};
~Config() override;
QVariant get(ConfigKey key);
QString getFileName();
void set(ConfigKey key, const QVariant& value);
void sync();
void resetToDefaults();
static Config* instance();
signals:
void changed(ConfigKey key);
private:
Config(const QString& fileName, QObject* parent = nullptr);
explicit Config(QObject* parent);
void init(const QString& configFileName);
static QPointer<Config> m_instance;
QScopedPointer<QSettings> m_settings;
QHash<QString, QVariant> m_defaults;
};
inline Config* config()
{
return Config::instance();
}
#endif //MONEROSERVICE_SETTINGS_H

@ -0,0 +1,86 @@
#include "Configurator.h"
#include "ui_Configurator.h"
#include "Config.h"
#include <QIcon>
Configurator::Configurator(QWidget *parent) :
QDialog(parent),
ui(new Ui::Configurator)
{
ui->setupUi(this);
// Basic settings
ui->lineMonerod->setText(config()->get(Config::pathToMonerod).toString());
ui->lineMonerod->setCursorPosition(0);
connect(ui->lineMonerod, &QLineEdit::textChanged, [this](const QString &text){
this->setConfig(Config::pathToMonerod, text);
});
ui->checkPruneBlockchain->setChecked(config()->get(Config::pruneBlockchain).toBool());
connect(ui->checkPruneBlockchain, &QCheckBox::toggled, [this](bool toggled){
this->setConfig(Config::pruneBlockchain, toggled);
});
ui->lineDataDir->setText(config()->get(Config::dataDir).toString());
connect(ui->lineDataDir, &QLineEdit::textChanged, [this](const QString &text){
this->setConfig(Config::dataDir, text);
});
ui->spinLimitSpeedDown->setValue(config()->get(Config::limitRateDown).toInt());
connect(ui->spinLimitSpeedDown, QOverload<int>::of(&QSpinBox::valueChanged), [this](int value){
this->setConfig(Config::limitRateDown, value);
});
// Advanced settings
ui->comboNetwork->setCurrentIndex(config()->get(Config::network).toInt());
connect(ui->comboNetwork, QOverload<int>::of(&QComboBox::currentIndexChanged), [this](int value){
this->setConfig(Config::network, value);
});
ui->comboLogLevel->setCurrentIndex(config()->get(Config::logLevel).toInt());
connect(ui->comboLogLevel, QOverload<int>::of(&QComboBox::currentIndexChanged), [this](int value){
this->setConfig(Config::logLevel, value);
});
ui->checkNoZeroMQ->setChecked(config()->get(Config::noZeroMQ).toBool());
connect(ui->checkNoZeroMQ, &QCheckBox::toggled, [this](bool toggled){
this->setConfig(Config::noZeroMQ, toggled);
});
ui->lineRPCBindIP->setText(config()->get(Config::RPCBindIP).toString());
connect(ui->lineRPCBindIP, &QLineEdit::textChanged, [this](const QString &text){
this->setConfig(Config::RPCBindIP, text);
});
ui->lineRPCBindPort->setText(config()->get(Config::RPCBindPort).toString());
connect(ui->lineP2PBindPort, &QLineEdit::textChanged, [this](const QString &text){
this->setConfig(Config::P2PBindPort, text);
});
ui->lineP2PBindIP->setText(config()->get(Config::P2PBindIP).toString());
connect(ui->lineP2PBindIP, &QLineEdit::textChanged, [this](const QString &text){
this->setConfig(Config::P2PBindIP, text);
});
ui->lineP2PBindPort->setText(config()->get(Config::P2PBindPort).toString());
connect(ui->lineP2PBindPort, &QLineEdit::textChanged, [this](const QString &text){
this->setConfig(Config::P2PBindPort, text);
});
this->adjustSize();
}
bool Configurator::configUpdated() const {
return m_configUpdated;
}
void Configurator::setConfig(Config::ConfigKey configKey, const QVariant &value) {
this->m_configUpdated = true;
config()->set(configKey, value);
}
Configurator::~Configurator()
{
delete ui;
}

@ -0,0 +1,27 @@
#ifndef MONEROSERVICE_CONFIGURATOR_H
#define MONEROSERVICE_CONFIGURATOR_H
#include <QDialog>
#include "Config.h"
namespace Ui {
class Configurator;
}
class Configurator : public QDialog
{
Q_OBJECT
public:
explicit Configurator(QWidget *parent = nullptr);
~Configurator() override;
bool configUpdated() const;
private:
void setConfig(Config::ConfigKey configKey, const QVariant &value);
Ui::Configurator *ui;
bool m_configUpdated = false;
};
#endif //MONEROSERVICE_CONFIGURATOR_H

@ -0,0 +1,345 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Configurator</class>
<widget class="QDialog" name="Configurator">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>692</width>
<height>585</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>500</width>
<height>0</height>
</size>
</property>
<property name="windowTitle">
<string>Config</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>1</number>
</property>
<widget class="QWidget" name="tab">
<attribute name="title">
<string>Basic</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Path to monerod:</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLineEdit" name="lineMonerod"/>
</item>
<item>
<widget class="QPushButton" name="btn_BrowseMonerodPath">
<property name="text">
<string>Browse</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_6">
<property name="title">
<string>Blockchain</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<widget class="QCheckBox" name="checkPruneBlockchain">
<property name="text">
<string>Prune blockchain</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Data directory:</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QLineEdit" name="lineDataDir">
<property name="placeholderText">
<string>Leave blank for default</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btn_BrowseDataDir">
<property name="text">
<string>Browse</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_7">
<property name="title">
<string>Network</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Limit download speed:</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinLimitSpeedDown">
<property name="maximum">
<number>0</number>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="tab_2">
<attribute name="title">
<string>Advanced</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<layout class="QFormLayout" name="formLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Network</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="comboNetwork">
<item>
<property name="text">
<string>Mainnet</string>
</property>
</item>
<item>
<property name="text">
<string>Stagenet</string>
</property>
</item>
<item>
<property name="text">
<string>Testnet</string>
</property>
</item>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_5">
<property name="text">
<string>Log level</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="comboLogLevel">
<item>
<property name="text">
<string>Default</string>
</property>
</item>
<item>
<property name="text">
<string>Info</string>
</property>
</item>
<item>
<property name="text">
<string>Debug</string>
</property>
</item>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>RPC port</string>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>P2P port</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>RPC bind IP</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="lineRPCBindIP">
<property name="placeholderText">
<string>127.0.0.1</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>P2P bind IP</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="lineP2PBindIP">
<property name="placeholderText">
<string>127.0.0.1</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="lineRPCBindPort">
<property name="placeholderText">
<string>18081</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QLineEdit" name="lineP2PBindPort">
<property name="placeholderText">
<string>18082</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="checkNoZeroMQ">
<property name="text">
<string>No ZeroMQ</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>Startup flags</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QLineEdit" name="lineStartupFlags"/>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>81</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>Configurator</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>Configurator</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

@ -0,0 +1,240 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2014-2021, The Monero Project.
#include "DaemonManager.h"
#include <QElapsedTimer>
#include <QFile>
#include <QMutexLocker>
#include <QThread>
#include <QFileInfo>
#include <QDir>
#include <QDebug>
#include <QUrl>
#include <QtConcurrent/QtConcurrent>
#include <QApplication>
#include <QProcess>
#include <QStorageInfo>
#include <QVariantMap>
#include <QVariant>
#include <QMap>
#include <utility>
bool DaemonManager::start(const QStringList &flags, int port)
{
if (!QFileInfo(m_monerod).isFile())
{
emit daemonStartFailure("\"" + QDir::toNativeSeparators(m_monerod) + "\" " + tr("executable is missing"));
return false;
}
m_port = port;
// prepare command line arguments and pass to monerod
QStringList arguments = flags;
arguments << "--check-updates" << "disabled";
qDebug() << "starting monerod " + m_monerod;
qDebug() << "With command line arguments " << arguments;
QMutexLocker locker(&m_daemonMutex);
m_daemon.reset(new QProcess());
// Connect output slots
connect(m_daemon.get(), &QProcess::readyReadStandardOutput, this, &DaemonManager::printOutput);
connect(m_daemon.get(), &QProcess::readyReadStandardError, this, &DaemonManager::printError);
// add state changed listener
connect(m_daemon.get(), &QProcess::stateChanged, this, &DaemonManager::stateChanged);
// Start monerod
m_daemon->start(m_monerod, arguments);
// Start start watcher
m_scheduler.run([this] {
if (startWatcher()) {
emit daemonStarted();
}
});
return true;
}
void DaemonManager::stop()
{
m_daemon->terminate();
m_scheduler.run([this]{
stopWatcher();
});
}
bool DaemonManager::isRunning() const {
return m_running;
}
bool DaemonManager::startWatcher()
{
// Check if daemon is started every 2 seconds
QElapsedTimer timer;
timer.start();
while(!m_app_exit && m_running) {
QThread::sleep(2);
if(!started()) {
qDebug() << "daemon not running. checking again in 2 seconds.";
} else {
qDebug() << "daemon is started. Waiting 5 seconds to let daemon catch up";
return true;
}
}
return false;
}
bool DaemonManager::stopWatcher()
{
// Check if daemon is running every 2 seconds. Kill if still running after 10 seconds
int counter = 0;
while(!m_app_exit && !m_running) {
QThread::sleep(2);
counter++;
if(!started()) {
return true;
} else {
qDebug() << "Daemon still running. " << counter;
if(counter >= 5) {
m_daemon->kill();
}
}
}
return false;
}
void DaemonManager::stateChanged(QProcess::ProcessState state)
{
qDebug() << "STATE CHANGED: " << state;
m_running = (state != QProcess::NotRunning);
if (state == QProcess::NotRunning) {
emit daemonStopped();
}
}
void DaemonManager::printOutput()
{
QByteArray byteArray = [this]() {
QMutexLocker locker(&m_daemonMutex);
return m_daemon->readAllStandardOutput();
}();
QStringList strLines = QString(byteArray).split("\n");
for (const auto& line: strLines) {
emit daemonConsoleUpdated(line);
}
}
void DaemonManager::printError()
{
QByteArray byteArray = [this]() {
QMutexLocker locker(&m_daemonMutex);
return m_daemon->readAllStandardError();
}();
QStringList strLines = QString(byteArray).split("\n");
for (const auto& line: strLines) {
emit daemonConsoleUpdated(line);
qDebug() << "Daemon ERROR: " + line;
}
}
bool DaemonManager::started()
{
QString status;
sendCommand({"sync_info"}, status);
qDebug() << status;
m_started = status.contains("Height:");
return m_started;
}
bool DaemonManager::sendCommand(const QStringList &cmd, QString &message) const
{
QProcess p;
QStringList external_cmd(cmd);
external_cmd << "--rpc-bind-port" << QString::number(m_port);
qDebug() << "sending external cmd: " << external_cmd;
p.start(m_monerod, external_cmd);
bool started = p.waitForFinished(-1);
message = p.readAllStandardOutput();
emit daemonConsoleUpdated(message);
return started;
}
void DaemonManager::sendCommandAsync(const QStringList &cmd, std::function<void(QVariantList)> callback) const
{
m_scheduler.run([this, cmd] {
QString message;
return QVariantList({sendCommand(cmd, message), message});
}, std::move(callback));
}
void DaemonManager::exit()
{
qDebug("DaemonManager: exit()");
m_app_exit = true;
}
//
//QVariantMap DaemonManager::validateDataDir(const QString &dataDir) const
//{
// QVariantMap result;
// bool valid = true;
// bool readOnly = false;
// int storageAvailable = 0;
// bool lmdbExists = true;
//
// QStorageInfo storage(dataDir);
// if (storage.isValid() && storage.isReady()) {
// if (storage.isReadOnly()) {
// readOnly = true;
// valid = false;
// }
//
// // Make sure there is 75GB storage available
// storageAvailable = storage.bytesAvailable()/1000/1000/1000;
// if (storageAvailable < 75) {
// valid = false;
// }
// } else {
// valid = false;
// }
//
//
// if (!QDir(dataDir+"/lmdb").exists()) {
// lmdbExists = false;
// valid = false;
// }
//
// result.insert("valid", valid);
// result.insert("lmdbExists", lmdbExists);
// result.insert("readOnly", readOnly);
// result.insert("storageAvailable", storageAvailable);
//
// return result;
//}
void DaemonManager::setMonerodPath(const QString &path) {
m_monerod = path;
}
DaemonManager::DaemonManager(QObject *parent)
: QObject(parent)
, m_scheduler(this)
{
}
DaemonManager::~DaemonManager()
{
m_scheduler.shutdownWaitForFinished();
}

@ -0,0 +1,64 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2014-2021, The Monero Project.
#ifndef DAEMONMANAGER_H
#define DAEMONMANAGER_H
#include <memory>
#include <QMutex>
#include <QObject>
#include <QUrl>
#include <QProcess>
#include <QVariantMap>
#include "FutureScheduler.h"
class DaemonManager : public QObject
{
Q_OBJECT
public:
explicit DaemonManager(QObject *parent = nullptr);
~DaemonManager() override;
bool start(const QStringList &flags, int port);
void stop();
void sendCommandAsync(const QStringList &cmd, std::function<void(QVariantList)> callback) const;
void exit();
// QVariantMap validateDataDir(const QString &dataDir) const;
void setMonerodPath(const QString &path);
bool isRunning() const;
private:
bool started();
bool sendCommand(const QStringList &cmd, QString &message) const;
bool startWatcher();
bool stopWatcher();
signals:
void daemonStarted() const;
void daemonStopped() const;
void daemonStartFailure(const QString &error) const;
void daemonConsoleUpdated(QString message) const;
public slots:
void printOutput();
void printError();
void stateChanged(QProcess::ProcessState state);
private:
std::unique_ptr<QProcess> m_daemon;
QMutex m_daemonMutex;
QString m_monerod;
bool m_running = false;
bool m_started = false;
bool m_app_exit = false;
int m_port;
mutable FutureScheduler m_scheduler;
};
#endif // DAEMONMANAGER_H

@ -0,0 +1,96 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2014-2021, The Monero Project.
#include "FutureScheduler.h"
FutureScheduler::FutureScheduler(QObject *parent)
: QObject(parent), Alive(0), Stopping(false)
{
static std::once_flag once;
std::call_once(once, []() {
QThreadPool::globalInstance()->setMaxThreadCount(4);
});
}
FutureScheduler::~FutureScheduler()
{
shutdownWaitForFinished();
}
void FutureScheduler::shutdownWaitForFinished() noexcept
{
QMutexLocker locker(&Mutex);
Stopping = true;
while (Alive > 0)
{
Condition.wait(&Mutex);
}
}
QPair<bool, QFuture<void>> FutureScheduler::run(std::function<void()> function) noexcept
{
return execute<void>([this, function](QFutureWatcher<void> *) {
return QtConcurrent::run([this, function] {
try
{
function();
}
catch (const std::exception &exception)
{
qWarning() << "Exception thrown from async function: " << exception.what();
}
done();
});
});
}
QPair<bool, QFuture<QVariantList>> FutureScheduler::run(std::function<QVariantList()> function, const std::function<void(QVariantList)> callback)
{
return execute<QVariantList>([this, function, callback](QFutureWatcher<QVariantList> *watcher) {
connect(watcher, &QFutureWatcher<QVariantList>::finished, [watcher, callback] {
callback(watcher->future().result());
});
return QtConcurrent::run([this, function] {
QVariantList result;
try
{
result = function();
}
catch (const std::exception &exception)
{
qWarning() << "Exception thrown from async function: " << exception.what();
}
done();
return result;
});
});
}
bool FutureScheduler::stopping() const noexcept
{
return Stopping;
}
bool FutureScheduler::add() noexcept
{
QMutexLocker locker(&Mutex);
if (Stopping)
{
return false;
}
++Alive;
return true;
}
void FutureScheduler::done() noexcept
{
{
QMutexLocker locker(&Mutex);
--Alive;
}
Condition.wakeAll();
}

@ -0,0 +1,67 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2014-2021, The Monero Project.
#ifndef FUTURE_SCHEDULER_H
#define FUTURE_SCHEDULER_H
#include <functional>
#include <QtConcurrent/QtConcurrent>
#include <QFuture>
#include <QMutex>
#include <QMutexLocker>
#include <QPair>
#include <QWaitCondition>
class FutureScheduler : public QObject
{
Q_OBJECT
public:
FutureScheduler(QObject *parent);
~FutureScheduler();
void shutdownWaitForFinished() noexcept;
QPair<bool, QFuture<void>> run(std::function<void()> function) noexcept;
QPair<bool, QFuture<QVariantList>> run(std::function<QVariantList()> function, const std::function<void(QVariantList)> callback);
bool stopping() const noexcept;
private:
bool add() noexcept;
void done() noexcept;
template<typename T>
QPair<bool, QFuture<T>> execute(std::function<QFuture<T>(QFutureWatcher<T> *)> makeFuture) noexcept
{
if (add())
{
try
{
auto *watcher = new QFutureWatcher<T>();
connect(watcher, &QFutureWatcher<T>::finished, [watcher] {
watcher->deleteLater();
});
watcher->setFuture(makeFuture(watcher));
return qMakePair(true, watcher->future());
}
catch (const std::exception &exception)
{
qCritical() << "Failed to schedule async function: " << exception.what();
done();
}
}
return qMakePair(false, QFuture<T>());
}
QFutureWatcher<void> schedule(std::function<void()> function);
private:
size_t Alive;
QWaitCondition Condition;
QMutex Mutex;
std::atomic<bool> Stopping;
};
#endif // FUTURE_SCHEDULER_H

@ -0,0 +1,5 @@
<!DOCTYPE RCC><RCC version="1.0">
<qresource prefix="/">
<file>assets/monero_grey.png</file>
</qresource>
</RCC>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

@ -0,0 +1,21 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2021, The Monero Project.
#include "mainwindow.h"
#include <QApplication>
#include <QResource>
int main(int argc, char *argv[])
{
Q_INIT_RESOURCE(assets);
QApplication a(argc, argv);
QApplication::setApplicationName("moneroservice");
QApplication::setOrganizationName("monero");
MainWindow w;
w.show();
return a.exec();
}

@ -0,0 +1,233 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2021, The Monero Project.
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "Configurator.h"
#include "Config.h"
#include <QMessageBox>
#include <QIcon>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
this->setWindowIcon(QIcon(":/assets/monero_grey.png"));
// Setup tray
m_trayIcon = new QSystemTrayIcon(QIcon(":/assets/monero_grey.png"));
m_trayIcon->show();
m_showWindow = m_trayMenu.addAction("Show window");
m_trayIcon->setContextMenu(&m_trayMenu);
// Daemon manager
daemonManager = new DaemonManager(this);
QString monerodPath = config()->get(Config::pathToMonerod).toString();
if (monerodPath.isEmpty()) {
monerodPath = this->defaultMonerodPath();
}
config()->set(Config::pathToMonerod, monerodPath);
daemonManager->setMonerodPath(monerodPath);
connect(daemonManager, &DaemonManager::daemonConsoleUpdated, this, &MainWindow::writeLogLine);
connect(m_showWindow, &QAction::triggered, [this]{
this->show();
this->raise();
this->setFocus();
});
connect(ui->btn_Configure, &QPushButton::clicked, this, &MainWindow::showConfigurator);
connect(ui->commandPrompt, &CommandLineEdit::commandExecuted, this, &MainWindow::sendCommand);
this->setStatus("not running");
connect(ui->btn_ToggleDaemon, &QPushButton::pressed, [this]{
if (daemonManager->isRunning()) {
this->setStatus("stopping");
daemonManager->stop();
} else {
QStringList flags = this->getStartupFlags();
this->setStatus("starting");
ui->btn_ToggleDaemon->setEnabled(false);
daemonManager->start(flags, this->getPort());
}
});
connect(daemonManager, &DaemonManager::daemonStarted, [this]{
this->setStatus("running");
ui->btn_ToggleDaemon->setEnabled(true);
ui->btn_ToggleDaemon->setText("Stop daemon");
});
connect(daemonManager, &DaemonManager::daemonStopped, [this]{
this->setStatus("stopped");
ui->btn_ToggleDaemon->setText("Start daemon");
});
// qApp->setStyleSheet(this->loadStylesheet(":/qdarkstyle/style.qss"));
this->adjustSize();
// showMinimized();
}
void MainWindow::writeLogLine(const QString &line) {
auto l = line.trimmed();
if (!l.isEmpty()) {
ui->logs->append(l);
}
}
void MainWindow::changeEvent(QEvent* e)
{
switch (e->type())
{
case QEvent::WindowStateChange:
{
if (this->windowState() & Qt::WindowMinimized)
{
QTimer::singleShot(250, this, SLOT(hide()));
}
break;
}
default:
break;
}
QMainWindow::changeEvent(e);
}
void MainWindow::sendCommand(const QStringList &command) {
daemonManager->sendCommandAsync(command, [](const QVariantList& l){
bool success = l[0].toBool();
QString message = l[1].toString();
qDebug() << QString("Command executed: %1, with message: %2").arg(success ? "Success" : "Fail", message);
});
}
void MainWindow::showConfigurator() {
auto *dialog = new Configurator(this);
dialog->exec();
if (dialog->configUpdated()) {
this->askRestartMonerod();
}
dialog->deleteLater();
}
void MainWindow::askRestartMonerod() {
QMessageBox::information(this, "Config Updated", "The config has been altered, do you want to restart monerod now?");
}
void MainWindow::setStatus(const QString &status) {
ui->labelStatus->setText(QString("Daemon status: %1").arg(status));
}
int MainWindow::getPort() {
int RPCBindPort = config()->get(Config::RPCBindPort).toInt();
if (RPCBindPort) {
return RPCBindPort;
}
switch (config()->get(Config::network).toInt()) {
case 0:
return 18081;
case 1:
return 38081;
case 2:
return 28081;
}
return 18081;
}
QStringList MainWindow::getStartupFlags() {
QStringList startupFlags;
if (config()->get(Config::pruneBlockchain).toBool()) {
startupFlags << "--prune-blockchain";
}
QString dataDir = config()->get(Config::dataDir).toString();
if (!dataDir.isEmpty()) {
// Todo: check if dir exists
startupFlags << "--data-dir" << dataDir;
}
int limitRateDown = config()->get(Config::limitRateDown).toInt();
if (limitRateDown > 0) {
startupFlags << "--limit-rate-down" << QString::number(limitRateDown);
}
switch (config()->get(Config::network).toInt()) {
case 1:
startupFlags << "--stagenet";
break;
case 2:
startupFlags << "--testnet";
break;
default:
break;
}
if (config()->get(Config::noZeroMQ).toBool()) {
startupFlags << "--no-zmq";
}
QString RPCBindIP = config()->get(Config::RPCBindIP).toString();
if (!RPCBindIP.isEmpty()) {
startupFlags << "--rpc-bind-ip" << RPCBindIP;
}
int RPCBindPort = config()->get(Config::RPCBindPort).toInt();
if (RPCBindPort > 0) {
startupFlags << "--rpc-bind-port" << QString::number(RPCBindPort);
}
QString P2PBindIP = config()->get(Config::P2PBindIP).toString();
if (!RPCBindIP.isEmpty()) {
startupFlags << "--p2p-bind-ip" << P2PBindIP;
}
int P2PBindPort = config()->get(Config::P2PBindPort).toInt();
if (RPCBindPort > 0) {
startupFlags << "--p2p-bind-port" << QString::number(P2PBindPort);
}
return startupFlags;
}
QString MainWindow::defaultMonerodPath() {
QString monerod;
// Platform dependent path to monerod
#ifdef Q_OS_WIN
monerod = QApplication::applicationDirPath() + "/monerod.exe";
#elif defined(Q_OS_UNIX)
monerod = QApplication::applicationDirPath() + "/monerod";
#endif
if (monerod.length() == 0) {
qCritical() << "no daemon binary defined for current platform";
}
return monerod;
}
QString MainWindow::loadStylesheet(const QString &resource) {
QFile f(resource);
if (!f.exists()) {
printf("Unable to set stylesheet, file not found\n");
f.close();
return "";
}
f.open(QFile::ReadOnly | QFile::Text);
QTextStream ts(&f);
QString data = ts.readAll();
f.close();
return data;
}
MainWindow::~MainWindow()
{
delete ui;
}

@ -0,0 +1,51 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2021, The Monero Project.
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QMenu>
#include <QLabel>
#include <QSystemTrayIcon>
#include "DaemonManager.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow() override;
private:
void writeLogLine(const QString &line);
void changeEvent(QEvent *e) override;
void showConfigurator();
void sendCommand(const QStringList &command);
void askRestartMonerod();
void setStatus(const QString &status);
QStringList getStartupFlags();
int getPort();
QString defaultMonerodPath();
QString loadStylesheet(const QString &resource);
Ui::MainWindow *ui;
QSystemTrayIcon *m_trayIcon;
QMenu m_trayMenu;
QAction *m_stopDaemon;
QAction *m_showWindow;
DaemonManager *daemonManager;
};
#endif // MAINWINDOW_H

@ -0,0 +1,109 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>828</width>
<height>724</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>750</width>
<height>650</height>
</size>
</property>
<property name="windowTitle">
<string>Monero Daemon Service</string>
</property>
<widget class="QWidget" name="centralWidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="spacing">
<number>0</number>
</property>
<item>
<widget class="QTextEdit" name="logs">
<property name="readOnly">
<bool>true</bool>
</property>
<property name="placeholderText">
<string>Logs are empty</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="CommandLineEdit" name="commandPrompt">
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="placeholderText">
<string>Enter command</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="labelStatus">
<property name="text">
<string>status</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="btn_ToggleDaemon">
<property name="text">
<string>Start daemon</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btn_Configure">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
<customwidget>
<class>CommandLineEdit</class>
<extends>QLineEdit</extends>
<header>CommandLineEdit.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

@ -0,0 +1,89 @@
<RCC>
<qresource>
<file>light/hmovetoolbar.svg</file>
<file>light/vmovetoolbar.svg</file>
<file>light/hsepartoolbar.svg</file>
<file>light/vsepartoolbars.svg</file>
<file>light/stylesheet-branch-end.svg</file>
<file>light/stylesheet-branch-end-closed.svg</file>
<file>light/stylesheet-branch-end-open.svg</file>
<file>light/stylesheet-vline.svg</file>
<file>light/stylesheet-branch-more.svg</file>
<file>light/branch_closed.svg</file>
<file>light/branch_closed-on.svg</file>
<file>light/branch_open.svg</file>
<file>light/branch_open-on.svg</file>
<file>light/down_arrow.svg</file>
<file>light/down_arrow_disabled.svg</file>
<file>light/down_arrow-hover.svg</file>
<file>light/left_arrow.svg</file>
<file>light/left_arrow_disabled.svg</file>
<file>light/right_arrow.svg</file>
<file>light/right_arrow_disabled.svg</file>
<file>light/up_arrow.svg</file>
<file>light/up_arrow_disabled.svg</file>
<file>light/up_arrow-hover.svg</file>
<file>light/sizegrip.svg</file>
<file>light/transparent.svg</file>
<file>light/close.svg</file>
<file>light/close-hover.svg</file>
<file>light/close-pressed.svg</file>
<file>light/undock.svg</file>
<file>light/undock-hover.svg</file>
<file>light/checkbox_checked-hover.svg</file>
<file>light/checkbox_checked.svg</file>
<file>light/checkbox_checked_disabled.svg</file>
<file>light/checkbox_indeterminate.svg</file>
<file>light/checkbox_indeterminate-hover.svg</file>
<file>light/checkbox_indeterminate_disabled.svg</file>
<file>light/checkbox_unchecked-hover.svg</file>
<file>light/checkbox_unchecked_disabled.svg</file>
<file>light/radio_checked-hover.svg</file>
<file>light/radio_checked.svg</file>
<file>light/radio_checked_disabled.svg</file>
<file>light/radio_unchecked-hover.svg</file>
<file>light/radio_unchecked_disabled.svg</file>
<file>dark/hmovetoolbar.svg</file>
<file>dark/vmovetoolbar.svg</file>
<file>dark/hsepartoolbar.svg</file>
<file>dark/vsepartoolbars.svg</file>
<file>dark/stylesheet-branch-end.svg</file>
<file>dark/stylesheet-branch-end-closed.svg</file>
<file>dark/stylesheet-branch-end-open.svg</file>
<file>dark/stylesheet-vline.svg</file>
<file>dark/stylesheet-branch-more.svg</file>
<file>dark/branch_closed.svg</file>
<file>dark/branch_closed-on.svg</file>
<file>dark/branch_open.svg</file>
<file>dark/branch_open-on.svg</file>
<file>dark/down_arrow.svg</file>
<file>dark/down_arrow_disabled.svg</file>
<file>dark/down_arrow-hover.svg</file>
<file>dark/left_arrow.svg</file>
<file>dark/left_arrow_disabled.svg</file>
<file>dark/right_arrow.svg</file>
<file>dark/right_arrow_disabled.svg</file>
<file>dark/up_arrow.svg</file>
<file>dark/up_arrow_disabled.svg</file>
<file>dark/up_arrow-hover.svg</file>
<file>dark/sizegrip.svg</file>
<file>dark/transparent.svg</file>
<file>dark/close.svg</file>
<file>dark/close-hover.svg</file>
<file>dark/close-pressed.svg</file>
<file>dark/undock.svg</file>
<file>dark/undock-hover.svg</file>
<file>dark/checkbox_checked.svg</file>
<file>dark/checkbox_checked_disabled.svg</file>
<file>dark/checkbox_indeterminate.svg</file>
<file>dark/checkbox_indeterminate_disabled.svg</file>
<file>dark/checkbox_unchecked.svg</file>
<file>dark/checkbox_unchecked_disabled.svg</file>
<file>dark/radio_checked.svg</file>
<file>dark/radio_checked_disabled.svg</file>
<file>dark/radio_unchecked.svg</file>
<file>dark/radio_unchecked_disabled.svg</file>
<file>light.qss</file>
<file>dark.qss</file>
</qresource>
</RCC>

File diff suppressed because it is too large Load Diff

@ -0,0 +1,3 @@
<svg width="6" height="9">
<path fill="#fff" fill-rule="evenodd" d="M1,8V1L5,4.5Z"/>
</svg>

After

Width:  |  Height:  |  Size: 94 B

@ -0,0 +1,3 @@
<svg width="12" height="18">
<path fill="#afafaf" d="M5,12V6L9,9Z"/>
</svg>

After

Width:  |  Height:  |  Size: 78 B

@ -0,0 +1,3 @@
<svg width="9" height="6">
<path fill="#fff" d="M1,1H8L4.5,5Z"/>
</svg>

After

Width:  |  Height:  |  Size: 74 B

@ -0,0 +1,3 @@
<svg width="18" height="12">
<path fill="#afafaf" d="M5.5,3H12.5L9,9Z"/>
</svg>

After

Width:  |  Height:  |  Size: 82 B

@ -0,0 +1,5 @@
<svg x="0px" y="0px" width="18px" height="18px" viewBox="0 0 18 18" enable-background="new 0 0 18 18" xml:space="preserve">
<path d="M2,2 h14 v14 h-0.9 v-13.1 h-13.1 z" fill="#58d3ff"/>
<path d="M16,16 h-14 v-14 h0.9 v13.1 h13.1 z" fill="#58d3ff"/>
<path d="M5,5 h8 v8 h-8 v-8 z" fill="#58d3ff" fill-rule="evenodd"/>
</svg>

After

Width:  |  Height:  |  Size: 330 B

@ -0,0 +1,5 @@
<svg x="0px" y="0px" width="18px" height="18px" viewBox="0 0 18 18" enable-background="new 0 0 18 18" xml:space="preserve">
<path d="M2,2 h14 v14 h-0.9 v-13.1 h-13.1 z" fill="#c8c9ca"/>
<path d="M16,16 h-14 v-14 h0.9 v13.1 h13.1 z" fill="#c8c9ca"/>
<path d="M5,5 h8 v8 h-8 v-8 z" fill="#c8c9ca" fill-rule="evenodd"/>
</svg>

After

Width:  |  Height:  |  Size: 330 B

@ -0,0 +1,7 @@
<svg x="0px" y="0px" width="18px" height="18px" viewBox="0 0 18 18" enable-background="new 0 0 18 18" xml:space="preserve">
<path d="M2,2 h14 v14 h-0.9 v-13.1 h-13.1 z" fill="#58d3ff"/>
<path d="M16,16 h-14 v-14 h0.9 v13.1 h13.1 z" fill="#58d3ff"/>
<path d="M5,5 h8 v8 h-0.9 v-7.1 h-7.1 z" fill="#58d3ff" fill-rule="evenodd"/>
<path d="M13,13 h-8 v-8 h0.9 v7.1 h7.1 z" fill="#58d3ff" fill-rule="evenodd"/>
<path d="M13,5 L 5,13 v-8 h8 z" fill="#58d3ff" fill-rule="evenodd"/>
</svg>

After

Width:  |  Height:  |  Size: 492 B

@ -0,0 +1,7 @@
<svg x="0px" y="0px" width="18px" height="18px" viewBox="0 0 18 18" enable-background="new 0 0 18 18" xml:space="preserve">
<path d="M2,2 h14 v14 h-0.9 v-13.1 h-13.1 z" fill="#c8c9ca"/>
<path d="M16,16 h-14 v-14 h0.9 v13.1 h13.1 z" fill="#c8c9ca"/>
<path d="M5,5 h8 v8 h-0.9 v-7.1 h-7.1 z" fill="#c8c9ca" fill-rule="evenodd"/>
<path d="M13,13 h-8 v-8 h0.9 v7.1 h7.1 z" fill="#c8c9ca" fill-rule="evenodd"/>
<path d="M13,5 L 5,13 v-8 h8 z" fill="#c8c9ca" fill-rule="evenodd"/>
</svg>

After

Width:  |  Height:  |  Size: 492 B

@ -0,0 +1,4 @@
<svg x="0px" y="0px" width="18px" height="18px" viewBox="0 0 18 18" enable-background="new 0 0 18 18" xml:space="preserve">
<path d="M2,2 h14 v14 h-0.9 v-13.1 h-13.1 z" fill="#58d3ff"/>
<path d="M16,16 h-14 v-14 h0.9 v13.1 h13.1 z" fill="#58d3ff"/>
</svg>

After

Width:  |  Height:  |  Size: 260 B

@ -0,0 +1,4 @@
<svg x="0px" y="0px" width="18px" height="18px" viewBox="0 0 18 18" enable-background="new 0 0 18 18" xml:space="preserve">
<path d="M2,2 h14 v14 h-0.9 v-13.1 h-13.1 z" fill="#c8c9ca"/>
<path d="M16,16 h-14 v-14 h0.9 v13.1 h13.1 z" fill="#c8c9ca"/>
</svg>

After

Width:  |  Height:  |  Size: 260 B

@ -0,0 +1,3 @@
<svg width="1200" height="1200">
<path d="M 600,1050 C 351.472,1050 150,848.528 150,600 150,351.472 351.472,150 600,150 c 248.528,0 450,201.472 450,450 0,248.528 -201.472,450 -450,450 z M 888.462,827.851 661.974,601.122 l 0,-2.244 226.488,-226.729 0,-60.611 -60.848,0 Q 727.339,411.986 627.043,512.451 613.524,525.358 600,538.267 l -226.487,-226.729 -61.975,0 0,60.611 L 538.026,600 311.538,826.729 l 0,61.733 60.848,0 q 34.363,-34.792 68.735,-69.59 L 600,661.733 l 226.487,226.729 61.975,0 0,-60.611 z" fill="#b37979"/>
</svg>

After

Width:  |  Height:  |  Size: 530 B

@ -0,0 +1,3 @@
<svg width="1200" height="1200">
<path d="M 600,1050 C 351.472,1050 150,848.528 150,600 150,351.472 351.472,150 600,150 c 248.528,0 450,201.472 450,450 0,248.528 -201.472,450 -450,450 z M 888.462,827.851 661.974,601.122 l 0,-2.244 226.488,-226.729 0,-60.611 -60.848,0 Q 727.339,411.986 627.043,512.451 613.524,525.358 600,538.267 l -226.487,-226.729 -61.975,0 0,60.611 L 538.026,600 311.538,826.729 l 0,61.733 60.848,0 q 34.363,-34.792 68.735,-69.59 L 600,661.733 l 226.487,226.729 61.975,0 0,-60.611 z" fill="#b33e3e"/>
</svg>

After

Width:  |  Height:  |  Size: 530 B

@ -0,0 +1,3 @@
<svg width="1200" height="1200">
<path d="M 600,1050 C 351.472,1050 150,848.528 150,600 150,351.472 351.472,150 600,150 c 248.528,0 450,201.472 450,450 0,248.528 -201.472,450 -450,450 z M 888.462,827.851 661.974,601.122 l 0,-2.244 226.488,-226.729 0,-60.611 -60.848,0 Q 727.339,411.986 627.043,512.451 613.524,525.358 600,538.267 l -226.487,-226.729 -61.975,0 0,60.611 L 538.026,600 311.538,826.729 l 0,61.733 60.848,0 q 34.363,-34.792 68.735,-69.59 L 600,661.733 l 226.487,226.729 61.975,0 0,-60.611 z" fill="#626568"/>
</svg>

After

Width:  |  Height:  |  Size: 530 B

@ -0,0 +1,3 @@
<svg x="0px" y="0px" width="9px" height="6px" viewBox="0 0 9 6" enable-background="new 0 0 9 6" xml:space="preserve">
<path d="M 1.1894592,0.91769718 4.5,4.2280182 7.8105408,0.91627648 c 0.1577125,-0.157702 0.4134624,-0.157702 0.5711749,0 0.1577124,0.15770202 0.1577124,0.41343492 0,0.57113692 l -3.5961283,3.5973102 0,0 0,0 c -0.1577124,0.1577019 -0.4134624,0.1577019 -0.5711748,0 L 0.6182843,1.4874134 c -0.1577124,-0.157702 -0.1577124,-0.4134349 0,-0.57113692 0.1577125,-0.15628131 0.4134624,-0.15628131 0.5711749,0.00142 z" fill="#3daee9"/>
</svg>

After

Width:  |  Height:  |  Size: 554 B

@ -0,0 +1,3 @@
<svg x="0px" y="0px" width="9px" height="6px" viewBox="0 0 9 6" enable-background="new 0 0 9 6" xml:space="preserve">
<path d="M 1.1894592,0.91769718 4.5,4.2280182 7.8105408,0.91627648 c 0.1577125,-0.157702 0.4134624,-0.157702 0.5711749,0 0.1577124,0.15770202 0.1577124,0.41343492 0,0.57113692 l -3.5961283,3.5973102 0,0 0,0 c -0.1577124,0.1577019 -0.4134624,0.1577019 -0.5711748,0 L 0.6182843,1.4874134 c -0.1577124,-0.157702 -0.1577124,-0.4134349 0,-0.57113692 0.1577125,-0.15628131 0.4134624,-0.15628131 0.5711749,0.00142 z" fill="#fff"/>
</svg>

After

Width:  |  Height:  |  Size: 551 B

@ -0,0 +1,3 @@
<svg x="0px" y="0px" width="9px" height="6px" viewBox="0 0 9 6" enable-background="new 0 0 9 6" xml:space="preserve">
<path d="M 1.1894592,0.91769718 4.5,4.2280182 7.8105408,0.91627648 c 0.1577125,-0.157702 0.4134624,-0.157702 0.5711749,0 0.1577124,0.15770202 0.1577124,0.41343492 0,0.57113692 l -3.5961283,3.5973102 0,0 0,0 c -0.1577124,0.1577019 -0.4134624,0.1577019 -0.5711748,0 L 0.6182843,1.4874134 c -0.1577124,-0.157702 -0.1577124,-0.4134349 0,-0.57113692 0.1577125,-0.15628131 0.4134624,-0.15628131 0.5711749,0.00142 z" fill="#b0b0b0"/>
</svg>

After

Width:  |  Height:  |  Size: 554 B

@ -0,0 +1,4 @@
<svg x="0px" y="0px" width="16px" height="64px" viewBox="0 0 16 64" enable-background="new 0 0 16 64" xml:space="preserve">
<rect fill="#5f5f5f" x="2" y="1" width="1" height="62.5"/>
<rect fill="#5f5f5f" x="9" y="1" width="1" height="62.5"/>
</svg>

After

Width:  |  Height:  |  Size: 253 B

@ -0,0 +1,3 @@
<svg x="0px" y="0px" width="7px" height="63px" viewBox="0 0 7 63" enable-background="new 0 0 7 63" xml:space="preserve">
<rect fill="#5f5f5f" x="2" y="13" width="1" height="37"/>
</svg>

After

Width:  |  Height:  |  Size: 188 B

@ -0,0 +1,3 @@
<svg x="0px" y="0px" width="6px" height="9px" viewBox="0 0 6 9" enable-background="new 0 0 6 9" xml:space="preserve">
<path d="m 5.0823028,1.1894593 -3.310321,3.3105408 3.3117417,3.3105408 c 0.157702,0.1577125 0.157702,0.4134624 0,0.5711749 -0.157702,0.1577123 -0.4134349,0.1577123 -0.5711369,0 l -3.59731017,-3.5961283 0,0 0,0 c -0.15770191,-0.1577124 -0.15770191,-0.4134624 0,-0.5711748 L 4.5125866,0.61828437 c 0.157702,-0.1577124 0.4134349,-0.1577124 0.5711369,0 0.1562813,0.1577125 0.1562813,0.41346243 -0.00142,0.57117493 z" fill="#fff"/>
</svg>

After

Width:  |  Height:  |  Size: 554 B

@ -0,0 +1,3 @@
<svg x="0px" y="0px" width="6px" height="9px" viewBox="0 0 6 9" enable-background="new 0 0 6 9" xml:space="preserve">
<path d="m 5.0823028,1.1894593 -3.310321,3.3105408 3.3117417,3.3105408 c 0.157702,0.1577125 0.157702,0.4134624 0,0.5711749 -0.157702,0.1577123 -0.4134349,0.1577123 -0.5711369,0 l -3.59731017,-3.5961283 0,0 0,0 c -0.15770191,-0.1577124 -0.15770191,-0.4134624 0,-0.5711748 L 4.5125866,0.61828437 c 0.157702,-0.1577124 0.4134349,-0.1577124 0.5711369,0 0.1562813,0.1577125 0.1562813,0.41346243 -0.00142,0.57117493 z" fill="#b0b0b0"/>
</svg>

After

Width:  |  Height:  |  Size: 557 B

@ -0,0 +1,5 @@
<svg x="0px" y="0px" width="20px" height="20px" viewBox="0 0 20 20" enable-background="new 0 0 20 20" xml:space="preserve">
<path d="M1,10a9,9 0 1,0 18,0 h-0.9 a8.1,8.1 0 1,1 -16.2,0 h-0.9" fill="#58d3ff" fill-rule="evenodd"/>
<path d="M1,10a9,9 0 1,1 18,0 h-0.9 a8.1,8.1 0 1,0 -16.2,0 h-0.9" fill="#58d3ff" fill-rule="evenodd"/>
<path d="M4,10a6,6 0 1,0 12,0a6,6 0 1,0 -12,0" fill="#58d3ff" fill-rule="evenodd"/>
</svg>

After

Width:  |  Height:  |  Size: 427 B

@ -0,0 +1,5 @@
<svg x="0px" y="0px" width="20px" height="20px" viewBox="0 0 20 20" enable-background="new 0 0 20 20" xml:space="preserve">
<path d="M1,10a9,9 0 1,0 18,0 h-0.9 a8.1,8.1 0 1,1 -16.2,0 h-0.9" fill="#c8c9ca" fill-rule="evenodd"/>
<path d="M1,10a9,9 0 1,1 18,0 h-0.9 a8.1,8.1 0 1,0 -16.2,0 h-0.9" fill="#c8c9ca" fill-rule="evenodd"/>
<path d="M4,10a6,6 0 1,0 12,0a6,6 0 1,0 -12,0" fill="#c8c9ca" fill-rule="evenodd"/>
</svg>

After

Width:  |  Height:  |  Size: 427 B

@ -0,0 +1,4 @@
<svg x="0px" y="0px" width="20px" height="20px" viewBox="0 0 20 20" enable-background="new 0 0 20 20" xml:space="preserve">
<path d="M1,10a9,9 0 1,0 18,0 h-0.9 a8.1,8.1 0 1,1 -16.2,0 h-0.9" fill="#58d3ff" fill-rule="evenodd"/>
<path d="M1,10a9,9 0 1,1 18,0 h-0.9 a8.1,8.1 0 1,0 -16.2,0 h-0.9" fill="#58d3ff" fill-rule="evenodd"/>
</svg>

After

Width:  |  Height:  |  Size: 341 B

@ -0,0 +1,4 @@
<svg x="0px" y="0px" width="20px" height="20px" viewBox="0 0 20 20" enable-background="new 0 0 20 20" xml:space="preserve">
<path d="M1,10a9,9 0 1,0 18,0 h-0.9 a8.1,8.1 0 1,1 -16.2,0 h-0.9" fill="#c8c9ca" fill-rule="evenodd"/>
<path d="M1,10a9,9 0 1,1 18,0 h-0.9 a8.1,8.1 0 1,0 -16.2,0 h-0.9" fill="#c8c9ca" fill-rule="evenodd"/>
</svg>

After

Width:  |  Height:  |  Size: 341 B

@ -0,0 +1,3 @@
<svg width="6" height="9">
<path d="m 0.9166972,1.1894593 3.310321,3.3105408 -3.3117417,3.3105408 c -0.157702,0.1577125 -0.157702,0.4134624 0,0.5711749 0.157702,0.1577123 0.4134349,0.1577123 0.5711369,0 l 3.5973102,-3.5961283 0,0 0,0 c 0.1577019,-0.1577124 0.1577019,-0.4134624 0,-0.5711748 L 1.4864134,0.61828437 c -0.157702,-0.1577124 -0.4134349,-0.1577124 -0.5711369,0 -0.1562813,0.1577125 -0.1562813,0.41346243 0.00142,0.57117493 z" fill="#fff"/>
</svg>

After

Width:  |  Height:  |  Size: 460 B

@ -0,0 +1,3 @@
<svg width="6" height="9">
<path d="m 0.9166972,1.1894593 3.310321,3.3105408 -3.3117417,3.3105408 c -0.157702,0.1577125 -0.157702,0.4134624 0,0.5711749 0.157702,0.1577123 0.4134349,0.1577123 0.5711369,0 l 3.5973102,-3.5961283 0,0 0,0 c 0.1577019,-0.1577124 0.1577019,-0.4134624 0,-0.5711748 L 1.4864134,0.61828437 c -0.157702,-0.1577124 -0.4134349,-0.1577124 -0.5711369,0 -0.1562813,0.1577125 -0.1562813,0.41346243 0.00142,0.57117493 z" fill="#b0b0b0"/>
</svg>

After

Width:  |  Height:  |  Size: 463 B

@ -0,0 +1,3 @@
<svg width="1000" height="1000">
<path fill="#b0b0b0" d="M22.1,1022.1L-22.1,977.9l1000-1000L1022.1,22.1Zm220,30L197.9,1007.9l1000-1000L1242.1,52.1Zm250,0L447.9,1007.9l1000-1000L1492.1,52.1Zm250,0L697.9,1007.9l1030-1030L1772.1,22.1Z"/>
</svg>

After

Width:  |  Height:  |  Size: 244 B

@ -0,0 +1,3 @@
<svg width="9" height="6">
<path d="M 1.1894592,5.0833028 4.5,1.7729818 7.8105408,5.0847235 c 0.1577125,0.157702 0.4134624,0.157702 0.5711749,0 0.1577124,-0.157702 0.1577124,-0.4134349 0,-0.5711369 l -3.5961283,-3.59731019 0,0 0,0 c -0.1577124,-0.1577019 -0.4134624,-0.1577019 -0.5711748,0 L 0.6182843,4.5135866 c -0.1577124,0.157702 -0.1577124,0.4134349 0,0.5711369 0.1577125,0.1562813 0.4134624,0.1562813 0.5711749,-0.00142 z" fill="#b0b0b0"/>
</svg>

After

Width:  |  Height:  |  Size: 455 B

@ -0,0 +1,4 @@
<svg width="81" height="58">
<rect id="VLine" fill="#626568" x="36" width="2" height="14"/>
<rect id="HLine" fill="#626568" x="65" y="28" height="1" width="28"/>
</svg>

After

Width:  |  Height:  |  Size: 173 B

@ -0,0 +1,4 @@
<svg width="81" height="58">
<rect id="VLine" fill="#626568" x="36" width="2" height="14"/>
<rect id="HLine" fill="#626568" x="65" y="28" height="1" width="28"/>
</svg>

After

Width:  |  Height:  |  Size: 173 B

@ -0,0 +1,4 @@
<svg width="81" height="58">
<rect id="VLine" fill="#626568" x="36" width="2" height="28"/>
<rect id="HLine" fill="#626568" x="36" y="28" height="1" width="57"/>
</svg>

After

Width:  |  Height:  |  Size: 173 B

@ -0,0 +1,4 @@
<svg width="81" height="58">
<rect id="VLine" fill="#626568" x="36" width="2" height="58"/>
<rect id="HLine" fill="#626568" x="36" y="30" height="1" width="44"/>
</svg>

After

Width:  |  Height:  |  Size: 173 B

@ -0,0 +1,3 @@
<svg width="81" height="58">
<rect fill="#626568" x="36" width="2" height="58"/>
</svg>

After

Width:  |  Height:  |  Size: 90 B

@ -0,0 +1 @@
<svg width="64" height="64"/>

After

Width:  |  Height:  |  Size: 30 B

@ -0,0 +1,5 @@
<svg width="1000" height="1000" >
<path id="BottomCircle" d="M100,500 a250,250, 0, 1,0, 800,0 M775,500 L500,775 L225,500 z" fill="#a2a2a2" />
<path id="TopCircle" d="M900,500 a250,250, 0, 1,0, -800,0 M225,500 L500,225 L775,500 z" fill="#a2a2a2" />
<path id="Inside" d="M275,500 L 500,725 L 725,500 L 500,275 z" fill="#a2a2a2" />
</svg>

After

Width:  |  Height:  |  Size: 343 B

@ -0,0 +1,3 @@
<svg width="1000" height="1000" >
<path d="M250,500 L 500,750 L 750,500 L 500,250 z" fill="none" stroke="#a2a2a2" stroke-width="50" />
</svg>

After

Width:  |  Height:  |  Size: 144 B

@ -0,0 +1,3 @@
<svg x="0px" y="0px" width="9px" height="6px" viewBox="0 0 9 6" enable-background="new 0 0 9 6" xml:space="preserve">
<path d="M 1.1894592,5.0833028 4.5,1.7729818 7.8105408,5.0847235 c 0.1577125,0.157702 0.4134624,0.157702 0.5711749,0 0.1577124,-0.157702 0.1577124,-0.4134349 0,-0.5711369 l -3.5961283,-3.59731019 0,0 0,0 c -0.1577124,-0.1577019 -0.4134624,-0.1577019 -0.5711748,0 L 0.6182843,4.5135866 c -0.1577124,0.157702 -0.1577124,0.4134349 0,0.5711369 0.1577125,0.1562813 0.4134624,0.1562813 0.5711749,-0.00142 z" fill="#3daee9"/>
</svg>

After

Width:  |  Height:  |  Size: 546 B

@ -0,0 +1,3 @@
<svg x="0px" y="0px" width="9px" height="6px" viewBox="0 0 9 6" enable-background="new 0 0 9 6" xml:space="preserve">
<path d="M 1.1894592,5.0833028 4.5,1.7729818 7.8105408,5.0847235 c 0.1577125,0.157702 0.4134624,0.157702 0.5711749,0 0.1577124,-0.157702 0.1577124,-0.4134349 0,-0.5711369 l -3.5961283,-3.59731019 0,0 0,0 c -0.1577124,-0.1577019 -0.4134624,-0.1577019 -0.5711748,0 L 0.6182843,4.5135866 c -0.1577124,0.157702 -0.1577124,0.4134349 0,0.5711369 0.1577125,0.1562813 0.4134624,0.1562813 0.5711749,-0.00142 z" fill="#fff"/>
</svg>

After

Width:  |  Height:  |  Size: 543 B

@ -0,0 +1,3 @@
<svg x="0px" y="0px" width="9px" height="6px" viewBox="0 0 9 6" enable-background="new 0 0 9 6" xml:space="preserve">
<path d="M 1.1894592,5.0833028 4.5,1.7729818 7.8105408,5.0847235 c 0.1577125,0.157702 0.4134624,0.157702 0.5711749,0 0.1577124,-0.157702 0.1577124,-0.4134349 0,-0.5711369 l -3.5961283,-3.59731019 0,0 0,0 c -0.1577124,-0.1577019 -0.4134624,-0.1577019 -0.5711748,0 L 0.6182843,4.5135866 c -0.1577124,0.157702 -0.1577124,0.4134349 0,0.5711369 0.1577125,0.1562813 0.4134624,0.1562813 0.5711749,-0.00142 z" fill="#b0b0b0"/>
</svg>

After

Width:  |  Height:  |  Size: 546 B

@ -0,0 +1,8 @@
<svg x="0px" y="0px" width="54px" height="10px" viewBox="0 0 54 10" enable-background="new 0 0 54 10" xml:space="preserve">
<rect id="Dark1" data-name="Dark1" fill="#292c31" x="16" y="1" width="4" height="8"/>
<rect id="Light1" data-name="Light1" fill="#7f8795" x="16" y="1" width="3" height="7"/>
<rect id="Dark2" data-name="Dark2" fill="#292c31" x="25" y="1" width="4" height="8"/>
<rect id="Light2" data-name="Light2" fill="#7f8795" x="25" y="1" width="3" height="7"/>
<rect id="Dark3" data-name="Dark3" fill="#292c31" x="34" y="1" width="4" height="8"/>
<rect id="Light3" data-name="Light3" fill="#7f8795" x="34" y="1" width="3" height="7"/>
</svg>

After

Width:  |  Height:  |  Size: 665 B

@ -0,0 +1,7 @@
<svg x="0px" y="0px" width="63px" height="7px" viewBox="0 0 63 7" enable-background="new 0 0 63 7" xml:space="preserve">
<rect id="Dark1" data-name="Dark1" fill="#292c31" x="25" y="1" width="1" height="5"/>
<rect id="Dark2" data-name="Dark2" fill="#292c31" x="38" y="1" width="1" height="5"/>
<rect id="Light1" data-name="Light1" fill="#7f8795" x="23" y="1" width="2" height="5"/>
<rect id="Light2" data-name="Light2" fill="#7f8795" x="30" y="1" width="2" height="5"/>
<rect id="Light3" data-name="Light3" fill="#7f8795" x="36" y="1" width="2" height="5"/>
</svg>

After

Width:  |  Height:  |  Size: 574 B

File diff suppressed because it is too large Load Diff

@ -0,0 +1,3 @@
<svg width="6" height="9">
<path fill="#000" fill-rule="evenodd" d="M1,8V1L5,4.5Z"/>
</svg>

After

Width:  |  Height:  |  Size: 94 B

@ -0,0 +1,3 @@
<svg width="12" height="18">
<path fill="#4b4b4b" d="M5,12V6L9,9Z"/>
</svg>

After

Width:  |  Height:  |  Size: 78 B

@ -0,0 +1,3 @@
<svg width="9" height="6">
<path fill="#000" d="M1,1H8L4.5,5Z"/>
</svg>

After

Width:  |  Height:  |  Size: 74 B

@ -0,0 +1,3 @@
<svg width="18" height="12">
<path fill="#4b4b4b" d="M5.5,3H12.5L9,9Z"/>
</svg>

After

Width:  |  Height:  |  Size: 82 B

@ -0,0 +1,5 @@
<svg x="0px" y="0px" width="18px" height="18px" viewBox="0 0 18 18" enable-background="new 0 0 18 18" xml:space="preserve">
<path d="M2,2 h14 v14 h-0.9 v-13.1 h-13.1 z" fill="#51c2fc"/>
<path d="M16,16 h-14 v-14 h0.9 v13.1 h13.1 z" fill="#51c2fc"/>
<path d="M5,5 h8 v8 h-8 v-8 z" fill="#51c2fc" fill-rule="evenodd"/>
</svg>

After

Width:  |  Height:  |  Size: 330 B

@ -0,0 +1,5 @@
<svg x="0px" y="0px" width="18px" height="18px" viewBox="0 0 18 18" enable-background="new 0 0 18 18" xml:space="preserve">
<path d="M2,2 h14 v14 h-0.9 v-13.1 h-13.1 z" fill="#3daee9"/>
<path d="M16,16 h-14 v-14 h0.9 v13.1 h13.1 z" fill="#3daee9"/>
<path d="M5,5 h8 v8 h-8 v-8 z" fill="#3daee9" fill-rule="evenodd"/>
</svg>

After

Width:  |  Height:  |  Size: 330 B

@ -0,0 +1,5 @@
<svg x="0px" y="0px" width="18px" height="18px" viewBox="0 0 18 18" enable-background="new 0 0 18 18" xml:space="preserve">
<path d="M2,2 h14 v14 h-0.9 v-13.1 h-13.1 z" fill="#31363B"/>
<path d="M16,16 h-14 v-14 h0.9 v13.1 h13.1 z" fill="#31363B"/>
<path d="M5,5 h8 v8 h-8 v-8 z" fill="#31363B" fill-rule="evenodd"/>
</svg>

After

Width:  |  Height:  |  Size: 330 B

@ -0,0 +1,7 @@
<svg x="0px" y="0px" width="18px" height="18px" viewBox="0 0 18 18" enable-background="new 0 0 18 18" xml:space="preserve">
<path d="M2,2 h14 v14 h-0.9 v-13.1 h-13.1 z" fill="#51c2fc"/>
<path d="M16,16 h-14 v-14 h0.9 v13.1 h13.1 z" fill="#51c2fc"/>
<path d="M5,5 h8 v8 h-0.9 v-7.1 h-7.1 z" fill="#51c2fc" fill-rule="evenodd"/>
<path d="M13,13 h-8 v-8 h0.9 v7.1 h7.1 z" fill="#51c2fc" fill-rule="evenodd"/>
<path d="M13,5 L 5,13 v-8 h8 z" fill="#51c2fc" fill-rule="evenodd"/>
</svg>

After

Width:  |  Height:  |  Size: 492 B

@ -0,0 +1,7 @@
<svg x="0px" y="0px" width="18px" height="18px" viewBox="0 0 18 18" enable-background="new 0 0 18 18" xml:space="preserve">
<path d="M2,2 h14 v14 h-0.9 v-13.1 h-13.1 z" fill="#3daee9"/>
<path d="M16,16 h-14 v-14 h0.9 v13.1 h13.1 z" fill="#3daee9"/>
<path d="M5,5 h8 v8 h-0.9 v-7.1 h-7.1 z" fill="#3daee9" fill-rule="evenodd"/>
<path d="M13,13 h-8 v-8 h0.9 v7.1 h7.1 z" fill="#3daee9" fill-rule="evenodd"/>
<path d="M13,5 L 5,13 v-8 h8 z" fill="#3daee9" fill-rule="evenodd"/>
</svg>

After

Width:  |  Height:  |  Size: 492 B

@ -0,0 +1,7 @@
<svg x="0px" y="0px" width="18px" height="18px" viewBox="0 0 18 18" enable-background="new 0 0 18 18" xml:space="preserve">
<path d="M2,2 h14 v14 h-0.9 v-13.1 h-13.1 z" fill="#31363B"/>
<path d="M16,16 h-14 v-14 h0.9 v13.1 h13.1 z" fill="#31363B"/>
<path d="M5,5 h8 v8 h-0.9 v-7.1 h-7.1 z" fill="#31363B" fill-rule="evenodd"/>
<path d="M13,13 h-8 v-8 h0.9 v7.1 h7.1 z" fill="#31363B" fill-rule="evenodd"/>
<path d="M13,5 L 5,13 v-8 h8 z" fill="#31363B" fill-rule="evenodd"/>
</svg>

After

Width:  |  Height:  |  Size: 492 B

@ -0,0 +1,4 @@
<svg x="0px" y="0px" width="18px" height="18px" viewBox="0 0 18 18" enable-background="new 0 0 18 18" xml:space="preserve">
<path d="M2,2 h14 v14 h-0.9 v-13.1 h-13.1 z" fill="#51c2fc"/>
<path d="M16,16 h-14 v-14 h0.9 v13.1 h13.1 z" fill="#51c2fc"/>
</svg>

After

Width:  |  Height:  |  Size: 260 B

@ -0,0 +1,4 @@
<svg x="0px" y="0px" width="18px" height="18px" viewBox="0 0 18 18" enable-background="new 0 0 18 18" xml:space="preserve">
<path d="M2,2 h14 v14 h-0.9 v-13.1 h-13.1 z" fill="#31363B"/>
<path d="M16,16 h-14 v-14 h0.9 v13.1 h13.1 z" fill="#31363B"/>
</svg>

After

Width:  |  Height:  |  Size: 260 B

@ -0,0 +1,3 @@
<svg width="1200" height="1200">
<path d="M 600,1050 C 351.472,1050 150,848.528 150,600 150,351.472 351.472,150 600,150 c 248.528,0 450,201.472 450,450 0,248.528 -201.472,450 -450,450 z M 888.462,827.851 661.974,601.122 l 0,-2.244 226.488,-226.729 0,-60.611 -60.848,0 Q 727.339,411.986 627.043,512.451 613.524,525.358 600,538.267 l -226.487,-226.729 -61.975,0 0,60.611 L 538.026,600 311.538,826.729 l 0,61.733 60.848,0 q 34.363,-34.792 68.735,-69.59 L 600,661.733 l 226.487,226.729 61.975,0 0,-60.611 z" fill="#dc7676"/>
</svg>

After

Width:  |  Height:  |  Size: 530 B

@ -0,0 +1,3 @@
<svg width="1200" height="1200">
<path d="M 600,1050 C 351.472,1050 150,848.528 150,600 150,351.472 351.472,150 600,150 c 248.528,0 450,201.472 450,450 0,248.528 -201.472,450 -450,450 z M 888.462,827.851 661.974,601.122 l 0,-2.244 226.488,-226.729 0,-60.611 -60.848,0 Q 727.339,411.986 627.043,512.451 613.524,525.358 600,538.267 l -226.487,-226.729 -61.975,0 0,60.611 L 538.026,600 311.538,826.729 l 0,61.733 60.848,0 q 34.363,-34.792 68.735,-69.59 L 600,661.733 l 226.487,226.729 61.975,0 0,-60.611 z" fill="#b33e3e"/>
</svg>

After

Width:  |  Height:  |  Size: 530 B

@ -0,0 +1,3 @@
<svg width="1200" height="1200">
<path d="M 600,1050 C 351.472,1050 150,848.528 150,600 150,351.472 351.472,150 600,150 c 248.528,0 450,201.472 450,450 0,248.528 -201.472,450 -450,450 z M 888.462,827.851 661.974,601.122 l 0,-2.244 226.488,-226.729 0,-60.611 -60.848,0 Q 727.339,411.986 627.043,512.451 613.524,525.358 600,538.267 l -226.487,-226.729 -61.975,0 0,60.611 L 538.026,600 311.538,826.729 l 0,61.733 60.848,0 q 34.363,-34.792 68.735,-69.59 L 600,661.733 l 226.487,226.729 61.975,0 0,-60.611 z" fill="#626568"/>
</svg>

After

Width:  |  Height:  |  Size: 530 B

@ -0,0 +1,3 @@
<svg x="0px" y="0px" width="9px" height="6px" viewBox="0 0 9 6" enable-background="new 0 0 9 6" xml:space="preserve">
<path d="M 1.1894592,0.91769718 4.5,4.2280182 7.8105408,0.91627648 c 0.1577125,-0.157702 0.4134624,-0.157702 0.5711749,0 0.1577124,0.15770202 0.1577124,0.41343492 0,0.57113692 l -3.5961283,3.5973102 0,0 0,0 c -0.1577124,0.1577019 -0.4134624,0.1577019 -0.5711748,0 L 0.6182843,1.4874134 c -0.1577124,-0.157702 -0.1577124,-0.4134349 0,-0.57113692 0.1577125,-0.15628131 0.4134624,-0.15628131 0.5711749,0.00142 z" fill="#3daee9"/>
</svg>

After

Width:  |  Height:  |  Size: 554 B

@ -0,0 +1,3 @@
<svg x="0px" y="0px" width="9px" height="6px" viewBox="0 0 9 6" enable-background="new 0 0 9 6" xml:space="preserve">
<path d="M 1.1894592,0.91769718 4.5,4.2280182 7.8105408,0.91627648 c 0.1577125,-0.157702 0.4134624,-0.157702 0.5711749,0 0.1577124,0.15770202 0.1577124,0.41343492 0,0.57113692 l -3.5961283,3.5973102 0,0 0,0 c -0.1577124,0.1577019 -0.4134624,0.1577019 -0.5711748,0 L 0.6182843,1.4874134 c -0.1577124,-0.157702 -0.1577124,-0.4134349 0,-0.57113692 0.1577125,-0.15628131 0.4134624,-0.15628131 0.5711749,0.00142 z" fill="#31363B"/>
</svg>

After

Width:  |  Height:  |  Size: 554 B

@ -0,0 +1,3 @@
<svg x="0px" y="0px" width="9px" height="6px" viewBox="0 0 9 6" enable-background="new 0 0 9 6" xml:space="preserve">
<path d="M 1.1894592,0.91769718 4.5,4.2280182 7.8105408,0.91627648 c 0.1577125,-0.157702 0.4134624,-0.157702 0.5711749,0 0.1577124,0.15770202 0.1577124,0.41343492 0,0.57113692 l -3.5961283,3.5973102 0,0 0,0 c -0.1577124,0.1577019 -0.4134624,0.1577019 -0.5711748,0 L 0.6182843,1.4874134 c -0.1577124,-0.157702 -0.1577124,-0.4134349 0,-0.57113692 0.1577125,-0.15628131 0.4134624,-0.15628131 0.5711749,0.00142 z" fill="#b0b0b0"/>
</svg>

After

Width:  |  Height:  |  Size: 554 B

@ -0,0 +1,5 @@
<svg x="0px" y="0px" width="16px" height="64px" viewBox="0 0 16 64" enable-background="new 0 0 16 64" xml:space="preserve">
<rect fill="#76797c" x="2" y="1" width="1" height="62.5"/>
<rect fill="#76797c" x="9" y="1" width="1" height="62.5"/>
</svg>

After

Width:  |  Height:  |  Size: 254 B

@ -0,0 +1,3 @@
<svg x="0px" y="0px" width="7px" height="63px" viewBox="0 0 7 63" enable-background="new 0 0 7 63" xml:space="preserve">
<rect fill="#76797c" x="2" y="13" width="1" height="37"/>
</svg>

After

Width:  |  Height:  |  Size: 188 B

@ -0,0 +1,3 @@
<svg x="0px" y="0px" width="6px" height="9px" viewBox="0 0 6 9" enable-background="new 0 0 6 9" xml:space="preserve">
<path d="m 5.0823028,1.1894593 -3.310321,3.3105408 3.3117417,3.3105408 c 0.157702,0.1577125 0.157702,0.4134624 0,0.5711749 -0.157702,0.1577123 -0.4134349,0.1577123 -0.5711369,0 l -3.59731017,-3.5961283 0,0 0,0 c -0.15770191,-0.1577124 -0.15770191,-0.4134624 0,-0.5711748 L 4.5125866,0.61828437 c 0.157702,-0.1577124 0.4134349,-0.1577124 0.5711369,0 0.1562813,0.1577125 0.1562813,0.41346243 -0.00142,0.57117493 z" fill="#31363B"/>
</svg>

After

Width:  |  Height:  |  Size: 557 B

@ -0,0 +1,3 @@
<svg x="0px" y="0px" width="6px" height="9px" viewBox="0 0 6 9" enable-background="new 0 0 6 9" xml:space="preserve">
<path d="m 5.0823028,1.1894593 -3.310321,3.3105408 3.3117417,3.3105408 c 0.157702,0.1577125 0.157702,0.4134624 0,0.5711749 -0.157702,0.1577123 -0.4134349,0.1577123 -0.5711369,0 l -3.59731017,-3.5961283 0,0 0,0 c -0.15770191,-0.1577124 -0.15770191,-0.4134624 0,-0.5711748 L 4.5125866,0.61828437 c 0.157702,-0.1577124 0.4134349,-0.1577124 0.5711369,0 0.1562813,0.1577125 0.1562813,0.41346243 -0.00142,0.57117493 z" fill="#b0b0b0"/>
</svg>

After

Width:  |  Height:  |  Size: 557 B

@ -0,0 +1,5 @@
<svg x="0px" y="0px" width="20px" height="20px" viewBox="0 0 20 20" enable-background="new 0 0 20 20" xml:space="preserve">
<path d="M1,10a9,9 0 1,0 18,0 h-0.9 a8.1,8.1 0 1,1 -16.2,0 h-0.9" fill="#51c2fc" fill-rule="evenodd"/>
<path d="M1,10a9,9 0 1,1 18,0 h-0.9 a8.1,8.1 0 1,0 -16.2,0 h-0.9" fill="#51c2fc" fill-rule="evenodd"/>
<path d="M4,10a6,6 0 1,0 12,0a6,6 0 1,0 -12,0" fill="#51c2fc" fill-rule="evenodd"/>
</svg>

After

Width:  |  Height:  |  Size: 427 B

@ -0,0 +1,5 @@
<svg x="0px" y="0px" width="20px" height="20px" viewBox="0 0 20 20" enable-background="new 0 0 20 20" xml:space="preserve">
<path d="M1,10a9,9 0 1,0 18,0 h-0.9 a8.1,8.1 0 1,1 -16.2,0 h-0.9" fill="#3daee9" fill-rule="evenodd"/>
<path d="M1,10a9,9 0 1,1 18,0 h-0.9 a8.1,8.1 0 1,0 -16.2,0 h-0.9" fill="#3daee9" fill-rule="evenodd"/>
<path d="M4,10a6,6 0 1,0 12,0a6,6 0 1,0 -12,0" fill="#3daee9" fill-rule="evenodd"/>
</svg>

After

Width:  |  Height:  |  Size: 427 B

@ -0,0 +1,5 @@
<svg x="0px" y="0px" width="20px" height="20px" viewBox="0 0 20 20" enable-background="new 0 0 20 20" xml:space="preserve">
<path d="M1,10a9,9 0 1,0 18,0 h-0.9 a8.1,8.1 0 1,1 -16.2,0 h-0.9" fill="#31363B" fill-rule="evenodd"/>
<path d="M1,10a9,9 0 1,1 18,0 h-0.9 a8.1,8.1 0 1,0 -16.2,0 h-0.9" fill="#31363B" fill-rule="evenodd"/>
<path d="M4,10a6,6 0 1,0 12,0a6,6 0 1,0 -12,0" fill="#31363B" fill-rule="evenodd"/>
</svg>

After

Width:  |  Height:  |  Size: 427 B

@ -0,0 +1,4 @@
<svg x="0px" y="0px" width="20px" height="20px" viewBox="0 0 20 20" enable-background="new 0 0 20 20" xml:space="preserve">
<path d="M1,10a9,9 0 1,0 18,0 h-0.9 a8.1,8.1 0 1,1 -16.2,0 h-0.9" fill="#51c2fc" fill-rule="evenodd"/>
<path d="M1,10a9,9 0 1,1 18,0 h-0.9 a8.1,8.1 0 1,0 -16.2,0 h-0.9" fill="#51c2fc" fill-rule="evenodd"/>
</svg>

After

Width:  |  Height:  |  Size: 341 B

@ -0,0 +1,4 @@
<svg x="0px" y="0px" width="20px" height="20px" viewBox="0 0 20 20" enable-background="new 0 0 20 20" xml:space="preserve">
<path d="M1,10a9,9 0 1,0 18,0 h-0.9 a8.1,8.1 0 1,1 -16.2,0 h-0.9" fill="#31363B" fill-rule="evenodd"/>
<path d="M1,10a9,9 0 1,1 18,0 h-0.9 a8.1,8.1 0 1,0 -16.2,0 h-0.9" fill="#31363B" fill-rule="evenodd"/>
</svg>

After

Width:  |  Height:  |  Size: 341 B

@ -0,0 +1,3 @@
<svg x="0px" y="0px" width="6px" height="9px" viewBox="0 0 6 9" enable-background="new 0 0 6 9" xml:space="preserve">
<path d="m 0.9166972,1.1894593 3.310321,3.3105408 -3.3117417,3.3105408 c -0.157702,0.1577125 -0.157702,0.4134624 0,0.5711749 0.157702,0.1577123 0.4134349,0.1577123 0.5711369,0 l 3.5973102,-3.5961283 0,0 0,0 c 0.1577019,-0.1577124 0.1577019,-0.4134624 0,-0.5711748 L 1.4864134,0.61828437 c -0.157702,-0.1577124 -0.4134349,-0.1577124 -0.5711369,0 -0.1562813,0.1577125 -0.1562813,0.41346243 0.00142,0.57117493 z" fill="#31363B"/>
</svg>

After

Width:  |  Height:  |  Size: 554 B

@ -0,0 +1,3 @@
<svg width="6" height="9">
<path d="m 0.9166972,1.1894593 3.310321,3.3105408 -3.3117417,3.3105408 c -0.157702,0.1577125 -0.157702,0.4134624 0,0.5711749 0.157702,0.1577123 0.4134349,0.1577123 0.5711369,0 l 3.5973102,-3.5961283 0,0 0,0 c 0.1577019,-0.1577124 0.1577019,-0.4134624 0,-0.5711748 L 1.4864134,0.61828437 c -0.157702,-0.1577124 -0.4134349,-0.1577124 -0.5711369,0 -0.1562813,0.1577125 -0.1562813,0.41346243 0.00142,0.57117493 z" fill="#b0b0b0"/>
</svg>

After

Width:  |  Height:  |  Size: 463 B

@ -0,0 +1,3 @@
<svg width="1000" height="1000">
<path fill="#b0b0b0" d="M22.1,1022.1L-22.1,977.9l1000-1000L1022.1,22.1Zm220,30L197.9,1007.9l1000-1000L1242.1,52.1Zm250,0L447.9,1007.9l1000-1000L1492.1,52.1Zm250,0L697.9,1007.9l1030-1030L1772.1,22.1Z"/>
</svg>

After

Width:  |  Height:  |  Size: 244 B

@ -0,0 +1,3 @@
<svg width="9" height="6">
<path d="M 1.1894592,5.0833028 4.5,1.7729818 7.8105408,5.0847235 c 0.1577125,0.157702 0.4134624,0.157702 0.5711749,0 0.1577124,-0.157702 0.1577124,-0.4134349 0,-0.5711369 l -3.5961283,-3.59731019 0,0 0,0 c -0.1577124,-0.1577019 -0.4134624,-0.1577019 -0.5711748,0 L 0.6182843,4.5135866 c -0.1577124,0.157702 -0.1577124,0.4134349 0,0.5711369 0.1577125,0.1562813 0.4134624,0.1562813 0.5711749,-0.00142 z" fill="#b0b0b0"/>
</svg>

After

Width:  |  Height:  |  Size: 455 B

@ -0,0 +1,4 @@
<svg width="81" height="58">
<rect id="VLine" fill="#bcbfc2" x="36" width="2" height="14"/>
<rect id="HLine" fill="#bcbfc2" x="65" y="28" height="1" width="28"/>
</svg>

After

Width:  |  Height:  |  Size: 173 B

@ -0,0 +1,4 @@
<svg width="81" height="58">
<rect id="VLine" fill="#bcbfc2" x="36" width="2" height="14"/>
<rect id="HLine" fill="#bcbfc2" x="65" y="28" height="1" width="28"/>
</svg>

After

Width:  |  Height:  |  Size: 173 B

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save