Improve sensor views

This commit is contained in:
Michael Zanetti 2021-10-22 18:00:21 +02:00
parent 84c0cffa44
commit 4f6f1ffbdc
12 changed files with 431 additions and 56 deletions

View File

@ -316,7 +316,10 @@ Interfaces::Interfaces(QObject *parent) : QAbstractListModel(parent)
addStateType("wirelessconnectable", "signalStrength", QVariant::UInt, false, tr("Signal strength"), tr("Signal strength changed"));
addInterface("watersensor", tr("Water sensors"), {"sensor"});
addStateType("watersensor", "watterDetected", QVariant::Double, false, tr("Water detected"), tr("Water detected changed"));
addStateType("watersensor", "waterDetected", QVariant::Double, false, tr("Water detected"), tr("Water detected changed"));
addInterface("firesensor", tr("Fire sensors"), {"sensor"});
addStateType("firesensor", "fireDetected", QVariant::Double, false, tr("Fire detected"), tr("Fire detected changed"));
}
int Interfaces::rowCount(const QModelIndex &parent) const

View File

@ -273,5 +273,6 @@
<file>ui/images/contact-group.svg</file>
<file>ui/images/zigbee/TI.svg</file>
<file>ui/images/car.svg</file>
<file>ui/images/sensors/fire.svg</file>
</qresource>
</RCC>

View File

@ -91,6 +91,7 @@ Page {
width: visible ? implicitWidth : 0
HeaderButton {
id: button
imageSource: "../images/system-update.svg"
color: Style.accentColor
visible: updatesModel.count > 0 || engine.systemController.updateRunning
@ -101,7 +102,7 @@ Page {
duration: 2000
loops: Animation.Infinite
running: engine.systemController.updateRunning
onStopped: icon.rotation = 0;
onStopped: button.rotation = 0;
}
PackagesFilterModel {
id: updatesModel

View File

@ -311,6 +311,8 @@ ApplicationWindow {
return Qt.resolvedUrl("images/sensors/water.svg")
case "waterlevelsensor":
return Qt.resolvedUrl("images/sensors/water.svg")
case "firesensor":
return Qt.resolvedUrl("images/sensors/fire.svg")
case "o2sensor":
return Qt.resolvedUrl("images/sensors/o2.svg")
case "phsensor":
@ -450,14 +452,11 @@ ApplicationWindow {
function interfaceToColor(name) {
// Try to load color map from style
print("checking color for name", name)
if (Style.interfaceColors[name]) {
print("have color for name", name, Style.interfaceColors[name])
return Style.interfaceColors[name];
}
if (styleBase.interfaceColors[name]) {
print("have color for name", name, styleBase.interfaceColors[name])
return styleBase.interfaceColors[name];
}

View File

@ -111,6 +111,7 @@ Item {
"ventilation": lightBlue,
"watersensor": lightBlue,
"waterlevelsensor": lightBlue,
"firesensor": red,
"phsensor": green,
"o2sensor": lightBlue,
"orpsensor": yellow,

View File

@ -44,6 +44,11 @@ Item {
property bool on: false
property alias showOnGradient: opacityMask.visible
property bool showProgress: false
property double progressFrom: 0
property double progressTo: 100
property double progress: 50
readonly property Item contentItem: background
signal clicked()
@ -95,7 +100,6 @@ Item {
source: gradient
maskSource: mask
Behavior on opacity { NumberAnimation { duration: Style.animationDuration } }
}
Item {

View File

@ -134,22 +134,22 @@ Item {
}
ctx.beginPath();
ctx.font = "" + app.hugeFont + "px " + Style.fontFamily;
ctx.font = "" + Style.hugeFont.pixelSize + "px " + Style.fontFamily;
ctx.fillStyle = Style.foregroundColor;
var roundedTargetTemp = Types.toUiValue(currentValue, root.targetTemperatureStateType.unit)
roundedTargetTemp = roundToPrecision(roundedTargetTemp).toFixed(1) + "°"
var size = ctx.measureText(roundedTargetTemp)
ctx.text(roundedTargetTemp, center.x - size.width / 2, center.y + app.hugeFont / 2);
ctx.text(roundedTargetTemp, center.x - size.width / 2, center.y + Style.hugeFont.pixelSize / 2);
ctx.fill();
ctx.closePath();
if (root.temperatureState) {
ctx.beginPath();
ctx.font = "" + app.largeFont + "px " + Style.fontFamily;
ctx.font = "" + Style.bigFont.pixelSize + "px " + Style.fontFamily;
var roundedTemp = Types.toUiValue(root.temperatureState.value, root.temperatureStateType.unit)
roundedTemp = roundToPrecision(roundedTemp) + "°"
size = ctx.measureText(roundedTemp)
ctx.text(roundedTemp, center.x - size.width / 2, center.y + app.hugeFont + app.margins);
ctx.text(roundedTemp, center.x - size.width / 2, center.y + Style.hugeFont.pixelSize + Style.margins);
ctx.fill();
ctx.closePath();
}

View File

@ -318,6 +318,7 @@ MainPageTile {
ListElement { ifaceName: "lightsensor"; stateName: "lightIntensity" }
ListElement { ifaceName: "watersensor"; stateName: "waterDetected" }
ListElement { ifaceName: "waterlevelsensor"; stateName: "waterLevel" }
ListElement { ifaceName: "firesensor"; stateName: "fireDetected" }
ListElement { ifaceName: "cosensor"; stateName: "co" }
ListElement { ifaceName: "co2sensor"; stateName: "co2" }
ListElement { ifaceName: "gassensor"; stateName: "gas" }

View File

@ -274,6 +274,9 @@ MainPageTile {
if (thing.thingClass.interfaces.indexOf("waterlevelsensor") >= 0) {
tmp.push({iface: "waterlevelsensor", state: "waterLevel"})
}
if (thing.thingClass.interfaces.indexOf("firesensor") >= 0) {
tmp.push({iface: "firesensor", state: "fireDetected"})
}
if (thing.thingClass.interfaces.indexOf("weather") >= 0) {
tmp.push({iface: "temperaturesensor", state: "temperature"});

View File

@ -90,6 +90,7 @@ ThingsListPageBase {
ListElement { interfaceName: "thermostat"; stateName: "targetTemperature" }
ListElement { interfaceName: "watersensor"; stateName: "waterDetected" }
ListElement { interfaceName: "waterlevelsensor"; stateName: "waterLevel" }
ListElement { interfaceName: "firesensor"; stateName: "fireDetected" }
ListElement { interfaceName: "o2sensor"; stateName: "o2saturation" }
ListElement { interfaceName: "phsensor"; stateName: "ph" }
ListElement { interfaceName: "orpsensor"; stateName: "orp" }
@ -111,6 +112,8 @@ ThingsListPageBase {
switch (model.interfaceName) {
case "closablesensor":
return sensorValueDelegate.stateValue && sensorValueDelegate.stateValue.value === true ? Style.green : Style.red;
case "firesensor":
return sensorValueDelegate.stateValue && sensorValueDelegate.stateValue.value === true ? Style.red : Style.iconColor;
default:
return app.interfaceToColor(model.interfaceName)
}
@ -138,6 +141,8 @@ ThingsListPageBase {
return sensorValueDelegate.stateValue && sensorValueDelegate.stateValue.value === true ? qsTr("Daytime") : qsTr("Nighttime");
case "watersensor":
return sensorValueDelegate.stateValue && sensorValueDelegate.stateValue.value === true ? qsTr("Wet") : qsTr("Dry");
case "firesensor":
return sensorValueDelegate.stateValue && sensorValueDelegate.stateValue.value === true ? qsTr("Fire") : qsTr("No fire");
case "heating":
return sensorValueDelegate.stateValue && sensorValueDelegate.stateValue.value === true ? qsTr("On") : qsTr("Off");
default:
@ -154,7 +159,7 @@ ThingsListPageBase {
}
Led {
id: led
visible: sensorValueDelegate.stateType && sensorValueDelegate.stateType.type.toLowerCase() === "bool" && ["presencesensor", "daylightsensor", "heating", "closablesensor", "watersensor"].indexOf(model.interfaceName) < 0
visible: sensorValueDelegate.stateType && sensorValueDelegate.stateType.type.toLowerCase() === "bool" && ["presencesensor", "daylightsensor", "heating", "closablesensor", "watersensor", "firesensor"].indexOf(model.interfaceName) < 0
state: visible && sensorValueDelegate.stateValue.value === true ? "on" : "off"
}
Item {

View File

@ -38,6 +38,42 @@ import "../customviews"
ThingPageBase {
id: root
property var interfaceStateMap: {
"temperaturesensor": "temperature",
"humiditysensor": "humidity",
"pressuresensor": "pressure",
"moisturesensor": "moisture",
"lightsensor": "lightIntensity",
"conductivitysensor": "conductivity",
"noisesensor": "noise",
"cosensor": "co",
"co2sensor": "co2",
"gassensor": "gas",
"presencesensor": "isPresent",
"daylightsensor": "daylight",
"closablesensor": "closed",
"watersensor": "waterDetected",
"firesensor": "fireDetected",
"waterlevelsensor": "waterLevel",
"phsensor": "ph",
"o2sensor": "o2saturation",
"orpsensor": "orp",
"airquality": "airQuality",
"indoorairquality": "indoorAirQuality"
}
ListModel {
id: sensorsModel
Component.onCompleted: {
var supportedInterfaces = Object.keys(interfaceStateMap)
for (var i = 0; i < supportedInterfaces.length; i++) {
if (root.thingClass.interfaces.indexOf(supportedInterfaces[i]) >= 0) {
append({name: supportedInterfaces[i]});
}
}
}
}
Flickable {
id: listView
anchors { fill: parent }
@ -45,65 +81,129 @@ ThingPageBase {
interactive: contentHeight > height
contentHeight: contentGrid.implicitHeight
GridLayout {
ColumnLayout {
id: contentGrid
width: parent.width - app.margins
anchors.horizontalCenter: parent.horizontalCenter
columns: Math.ceil(width / 600)
rowSpacing: 0
columnSpacing: 0
width: parent.width
spacing: Style.margins
Repeater {
model: ListModel {
Component.onCompleted: {
var supportedInterfaces = ["temperaturesensor", "humiditysensor", "pressuresensor", "moisturesensor", "lightsensor", "conductivitysensor", "noisesensor", "cosensor", "co2sensor", "gassensor", "presencesensor", "daylightsensor", "closablesensor", "watersensor", "phsensor", "o2sensor", "orpsensor", "waterlevelsensor"]
for (var i = 0; i < supportedInterfaces.length; i++) {
if (root.thingClass.interfaces.indexOf(supportedInterfaces[i]) >= 0) {
append({name: supportedInterfaces[i]});
Flow {
id: flow
Layout.fillWidth: true
Layout.leftMargin: sensorsModel.count == 1 ? Style.hugeMargins : Style.bigMargins
Layout.rightMargin: sensorsModel.count == 1 ? Style.hugeMargins : Style.bigMargins
Layout.preferredHeight: cellWidth * Math.min(400, Math.ceil(flowRepeater.count / columns))
property int columns: Math.min(flowRepeater.count, Math.floor(listView.width / 150))
property int cellWidth: width / columns
property int totalRows: flowRepeater.count / columns
// columns: 2// Math.ceil(width / 600)
// columnSpacing: Style.margins
// rowSpacing: Style.margins
Repeater {
id: flowRepeater
model: sensorsModel
delegate: Item {
width: Math.floor(flow.width / itemsInRow)
height: Math.min(400, flow.cellWidth)
property int row: Math.floor(index / flow.columns)
property int itemsInRow: row < flow.totalRows ? flow.columns : (flowRepeater.count % flow.columns)
CircleBackground {
id: background
anchors.centerIn: parent
width: Math.min(parent.width, parent.height) - Style.margins
height: width
readonly property StateType sensorStateType: root.thing.thingClass.stateTypes.findByName(interfaceStateMap[modelData])
readonly property State sensorState: root.thing.stateByName(interfaceStateMap[modelData])
onColor: app.interfaceToColor(modelData)
on: sensorStateType.type.toLowerCase() == "bool" && sensorState.value === true
iconSource: [
"closablesensor",
"presencesensor",
"daylightsensor",
"firesensor",
"watersensor"
].indexOf(modelData) >= 0 ? app.interfaceToIcon(modelData) : ""
Loader {
anchors.centerIn: parent
width: background.contentItem.width
height: background.contentItem.height
property StateType stateType: root.thingClass.stateTypes.findByName(interfaceStateMap[modelData])
property State state: root.thing.stateByName(interfaceStateMap[modelData])
property string interfaceName: modelData
property var minValue: {
if (["temperaturesensor"].indexOf(modelData) >= 0) {
return Types.toUiValue(-50, Types.UnitDegreeCelsius)
}
return state.minValue
}
property var maxValue: {
if (["temperaturesensor"].indexOf(modelData) >= 0) {
return Types.toUiValue(50, Types.UnitDegreeCelsius)
}
return state.maxValue
}
sourceComponent: {
var handledInterfaces = [
"humiditysensor",
"o2sensor",
"temperaturesensor",
"moisturesensor",
"co2sensor",
"conductivitysensor",
"cosensor",
"co2sensor",
"gassensor",
"lightsensor",
"orpsensor",
"phsensor",
"pressuresensor",
"waterlevelsensor",
"windspeedsensor"
]
if (handledInterfaces.indexOf(modelData) >= 0) {
return progressComponent
}
}
}
}
}
}
}
delegate: Loader {
id: loader
Layout.fillWidth: true
Layout.preferredHeight: item.implicitHeight
property StateType stateType: root.thingClass.stateTypes.findByName(interfaceStateMap[modelData])
property State state: root.thing.stateByName(interfaceStateMap[modelData])
property string interfaceName: modelData
GridLayout {
columns: Math.ceil(width / 600)
rowSpacing: 0
columnSpacing: 0
// sourceComponent: stateType && stateType.type.toLowerCase() === "bool" ? boolComponent : graphComponent
sourceComponent: graphComponent
Repeater {
model: sensorsModel
delegate: Loader {
id: loader
Layout.fillWidth: true
Layout.preferredHeight: item.implicitHeight
property StateType stateType: root.thingClass.stateTypes.findByName(interfaceStateMap[modelData])
property State state: root.thing.stateByName(interfaceStateMap[modelData])
property string interfaceName: modelData
// sourceComponent: stateType && stateType.type.toLowerCase() === "bool" ? boolComponent : graphComponent
sourceComponent: graphComponent
property var interfaceStateMap: {
"temperaturesensor": "temperature",
"humiditysensor": "humidity",
"pressuresensor": "pressure",
"moisturesensor": "moisture",
"lightsensor": "lightIntensity",
"conductivitysensor": "conductivity",
"noisesensor": "noise",
"cosensor": "co",
"co2sensor": "co2",
"gassensor": "gas",
"presencesensor": "isPresent",
"daylightsensor": "daylight",
"closablesensor": "closed",
"watersensor": "waterDetected",
"waterlevelsensor": "waterLevel",
"phsensor": "ph",
"o2sensor": "o2saturation",
"orpsensor": "orp"
}
}
}
}
Component {
id: graphComponent
@ -120,7 +220,7 @@ ThingPageBase {
Binding {
target: graph
property: "title"
when: ["presencesensor", "daylightsensor", "closablesensor", "watersensor"].indexOf(graph.interfaceName) >= 0
when: ["presencesensor", "daylightsensor", "closablesensor", "watersensor", "firesensor"].indexOf(graph.interfaceName) >= 0
value: {
switch (graph.interfaceName) {
case "presencesensor":
@ -131,6 +231,8 @@ ThingPageBase {
return graph.state.value === true ? qsTr("Closed") : qsTr("Open")
case "watersensor":
return graph.state.value === true ? qsTr("Wet") : qsTr("Dry")
case "firesensor":
return graph.state.value === true ? qsTr("Fire") : qsTr("No fire")
}
}
}
@ -225,5 +327,67 @@ ThingPageBase {
}
}
}
Component {
id: progressComponent
Canvas {
id: progressCanvas
property string interfaceName: parent.interfaceName
property StateType stateType: parent.stateType
property State state: parent.state
property var minValue: parent.minValue
property var maxValue: parent.maxValue
Label {
anchors.centerIn: parent
width: parent.width * 0.6
text: Types.toUiValue(progressCanvas.state.value, progressCanvas.stateType.unit).toFixed(1) + " " + Types.toUiUnit(progressCanvas.stateType.unit)
font.pixelSize: Math.min(Style.hugeFont.pixelSize, parent.height / 6)
wrapMode: Text.WordWrap
horizontalAlignment: Text.AlignHCenter
}
onPaint: {
var ctx = getContext("2d");
ctx.reset();
ctx.beginPath()
ctx.fillStyle = Style.foregroundColor
ctx.translate(width / 2, height / 2)
ctx.rotate(135 * Math.PI / 180)
ctx.lineCap = "round"
ctx.lineWidth = width * .1
ctx.beginPath()
ctx.strokeStyle = Style.tileOverlayColor
var startAngle = 0
var endAngle = 270
var radStart = startAngle * Math.PI/180;
var radEnd = endAngle * Math.PI/180;
ctx.arc(0, 0, width / 2 - ctx.lineWidth / 2, radStart, radEnd)
ctx.stroke()
ctx.closePath()
ctx.beginPath()
ctx.strokeStyle = app.interfaceToColor(progressCanvas.interfaceName)
var progress = (progressCanvas.state.value - progressCanvas.minValue) / (progressCanvas.maxValue - progressCanvas.minValue)
radEnd *= progress
ctx.arc(0, 0, width / 2 - ctx.lineWidth / 2, radStart, radEnd)
ctx.stroke()
ctx.closePath()
}
ColorIcon {
anchors.centerIn: parent
anchors.verticalCenterOffset: progressCanvas.height / 2 - height
name: app.interfaceToIcon(progressCanvas.interfaceName)
size: Math.min(Style.bigIconSize, parent.height / 5)
color: app.interfaceToColor(progressCanvas.interfaceName)
}
}
}
}

View File

@ -0,0 +1,193 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="96"
height="96"
id="svg4874"
version="1.1"
inkscape:version="1.0.1 (1.0.1+r74)"
viewBox="0 0 96 96.000001"
sodipodi:docname="heating.svg">
<defs
id="defs4876" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="2.245269"
inkscape:cx="90.885132"
inkscape:cy="30.463907"
inkscape:document-units="px"
inkscape:current-layer="g4780"
showgrid="true"
showborder="true"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:snap-bbox="true"
inkscape:bbox-paths="true"
inkscape:bbox-nodes="true"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:snap-bbox-midpoints="true"
inkscape:object-paths="true"
inkscape:snap-intersection-paths="true"
inkscape:object-nodes="true"
inkscape:snap-smooth-nodes="true"
inkscape:snap-midpoints="true"
inkscape:snap-object-midpoints="true"
inkscape:snap-center="true"
showguides="true"
inkscape:guide-bbox="true"
inkscape:snap-global="true"
inkscape:locked="false"
inkscape:document-rotation="0"
inkscape:window-width="1380"
inkscape:window-height="873"
inkscape:window-x="60"
inkscape:window-y="27"
inkscape:window-maximized="1">
<inkscape:grid
type="xygrid"
id="grid5451"
empspacing="8" />
<sodipodi:guide
orientation="1,0"
position="8,-8.0000001"
id="guide4063"
inkscape:locked="false" />
<sodipodi:guide
orientation="1,0"
position="4,-8.0000001"
id="guide4065"
inkscape:locked="false" />
<sodipodi:guide
orientation="0,1"
position="-8,88.000001"
id="guide4067"
inkscape:locked="false" />
<sodipodi:guide
orientation="0,1"
position="-8,92.000001"
id="guide4069"
inkscape:locked="false" />
<sodipodi:guide
orientation="0,1"
position="104,4"
id="guide4071"
inkscape:locked="false" />
<sodipodi:guide
orientation="0,1"
position="-5,8.0000001"
id="guide4073"
inkscape:locked="false" />
<sodipodi:guide
orientation="1,0"
position="88,-8.0000001"
id="guide4077"
inkscape:locked="false" />
<sodipodi:guide
orientation="0,1"
position="-8,84.000001"
id="guide4074"
inkscape:locked="false" />
<sodipodi:guide
orientation="1,0"
position="12,-8.0000001"
id="guide4076"
inkscape:locked="false" />
<sodipodi:guide
orientation="1,0"
position="84,-8.0000001"
id="guide4080"
inkscape:locked="false" />
<sodipodi:guide
position="48,-8.0000001"
orientation="1,0"
id="guide4170"
inkscape:locked="false" />
<sodipodi:guide
position="-8,48"
orientation="0,1"
id="guide4172"
inkscape:locked="false" />
<sodipodi:guide
position="92,-8.0000001"
orientation="1,0"
id="guide4760"
inkscape:locked="false" />
<sodipodi:guide
position="115,12"
orientation="0,1"
id="guide4269"
inkscape:locked="false" />
</sodipodi:namedview>
<metadata
id="metadata4879">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(67.857146,-78.50504)">
<g
transform="matrix(0,-1,-1,0,373.50506,516.50504)"
id="g4845"
style="display:inline">
<g
inkscape:export-ydpi="90"
inkscape:export-xdpi="90"
inkscape:export-filename="next01.png"
transform="matrix(-0.9996045,0,0,1,575.94296,-611.00001)"
id="g4778"
inkscape:label="Layer 1">
<g
transform="matrix(-1,0,0,1,575.99999,611)"
id="g4780"
style="display:inline">
<rect
style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;stroke:none;stroke-width:4;marker:none;enable-background:accumulate"
id="rect4782"
width="96.037987"
height="96"
x="-438.00244"
y="345.36221"
transform="scale(-1,1)" />
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:35.0587;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 353.8481,375.62826 c 4.51127,-4.50011 10.73477,-7.28703 17.61131,-7.30539 18.52405,1.03935 26.52722,17.03935 58.53988,24.91256 -1.1e-4,0.003 -0.005,0.0108 -0.008,0.0135 -0.002,0.003 -0.0108,0.008 -0.0135,0.0163 l -0.0163,0.0162 c -0.002,0.003 -0.008,0.0108 -0.008,0.0135 -31.96686,8.06729 -41.25206,24.68467 -58.3512,25.11489 -9.16872,0.0244 -17.19864,-4.88762 -21.58349,-12.22706 2.7374,2.44304 6.26672,3.92073 10.11771,3.91046 1.72033,-0.005 3.37088,-0.32156 4.91812,-0.87026 0.15735,-0.0558 0.31961,-0.10129 0.47482,-0.16223 1.31752,-0.42764 11.44887,-9.69851 27.79203,-15.6935 l 0.0934,-0.003 0.005,-0.0108 0.0135,-0.0108 0.008,-0.008 0.008,-0.008 c -0.008,-0.005 -0.019,-0.0135 -0.0301,-0.0217 0.0108,-0.005 0.019,-0.008 0.0303,-0.0135 l -0.008,-0.008 -0.008,-0.008 -0.0108,-0.0135 -0.003,-0.0108 -0.0934,-0.005 c -17.34846,-5.88391 -26.56285,-15.12908 -27.88283,-15.54974 -0.15573,-0.0598 -0.31801,-0.10427 -0.47558,-0.15952 -1.55041,-0.54039 -3.20262,-0.83993 -4.92291,-0.83536 -3.85099,0.0108 -7.36894,1.49781 -10.09199,3.95553 1.08552,-1.84068 2.3961,-3.53054 3.89995,-5.03048 z"
id="path4339"
sodipodi:nodetypes="cccccccccscccccccccccccccccsccc" />
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:22.784;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 376.50844,359.07051 c 2.9318,-2.92454 6.97633,-4.73571 11.44527,-4.74764 12.03844,0.67545 17.23956,11.07356 38.044,16.19022 -7e-5,0.002 -0.003,0.007 -0.005,0.009 -10e-4,0.002 -0.007,0.005 -0.009,0.0106 l -0.0106,0.0105 c -0.001,0.002 -0.005,0.007 -0.005,0.009 -20.77468,5.24278 -26.80896,16.04211 -37.92138,16.3217 -5.95859,0.0159 -11.17708,-3.17637 -14.02672,-7.94614 1.77899,1.58769 4.07263,2.54801 6.57532,2.54134 1.11801,-0.003 2.19067,-0.20898 3.19619,-0.56557 0.10226,-0.0363 0.20771,-0.0658 0.30858,-0.10543 0.85623,-0.27792 7.44041,-6.30288 18.06153,-10.19892 l 0.0607,-0.002 0.003,-0.007 0.009,-0.007 0.005,-0.005 0.005,-0.005 c -0.005,-0.003 -0.0123,-0.009 -0.0196,-0.0141 0.007,-0.003 0.0124,-0.005 0.0197,-0.009 l -0.005,-0.005 -0.005,-0.005 -0.007,-0.009 -0.002,-0.007 -0.0607,-0.003 c -11.27445,-3.82384 -17.26271,-9.83211 -18.12055,-10.10549 -0.1012,-0.0389 -0.20666,-0.0678 -0.30907,-0.10367 -1.00758,-0.35119 -2.08132,-0.54586 -3.19931,-0.54289 -2.50268,0.007 -4.78893,0.9734 -6.55859,2.57063 0.70545,-1.19622 1.55718,-2.29443 2.5345,-3.26922 z"
id="path852"
sodipodi:nodetypes="cccccccccscccccccccccccccccsccc" />
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:22.784;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
d="m 376.50844,403.07051 c 2.9318,-2.92454 6.97633,-4.73571 11.44527,-4.74764 12.03844,0.67545 17.23956,11.07356 38.044,16.19022 -7e-5,0.002 -0.003,0.007 -0.005,0.009 -10e-4,0.002 -0.007,0.005 -0.009,0.0106 l -0.0106,0.0105 c -0.001,0.002 -0.005,0.007 -0.005,0.009 -20.77468,5.24278 -26.80896,16.04211 -37.92138,16.3217 -5.95859,0.0159 -11.17708,-3.17637 -14.02672,-7.94614 1.77899,1.58769 4.07263,2.54801 6.57532,2.54134 1.11801,-0.003 2.19067,-0.20898 3.19619,-0.56557 0.10226,-0.0363 0.20771,-0.0658 0.30858,-0.10543 0.85623,-0.27792 7.44041,-6.30288 18.06153,-10.19892 l 0.0607,-0.002 0.003,-0.007 0.009,-0.007 0.005,-0.005 0.005,-0.005 c -0.005,-0.003 -0.0123,-0.009 -0.0196,-0.0141 0.007,-0.003 0.0124,-0.005 0.0197,-0.009 l -0.005,-0.005 -0.005,-0.005 -0.007,-0.009 -0.002,-0.007 -0.0607,-0.003 c -11.27445,-3.82384 -17.26271,-9.83211 -18.12055,-10.10549 -0.1012,-0.0389 -0.20666,-0.0678 -0.30907,-0.10367 -1.00758,-0.35119 -2.08132,-0.54586 -3.19931,-0.54289 -2.50268,0.007 -4.78893,0.9734 -6.55859,2.57063 0.70545,-1.19622 1.55718,-2.29443 2.5345,-3.26922 z"
id="path854"
sodipodi:nodetypes="cccccccccscccccccccccccccccsccc" />
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB