feat: show qr codes
This commit is contained in:
parent
c3a5fdabc7
commit
637484bd79
|
@ -52,3 +52,6 @@
|
|||
[submodule "vendor/nim-metrics"]
|
||||
path = vendor/nim-metrics
|
||||
url = https://github.com/status-im/nim-metrics
|
||||
[submodule "vendor/QR-Code-generator"]
|
||||
path = vendor/QR-Code-generator
|
||||
url = https://github.com/status-im/QR-Code-generator
|
||||
|
|
11
Makefile
11
Makefile
|
@ -150,9 +150,16 @@ $(STATUSGO): | deps
|
|||
+ cd vendor/status-go && \
|
||||
$(MAKE) statusgo-library $(HANDLE_OUTPUT)
|
||||
|
||||
nim_status_client: | $(DOTHERSIDE) $(STATUSGO) deps
|
||||
QRCODEGEN := vendor/QR-Code-generator/c/libqrcodegen.a
|
||||
|
||||
$(QRCODEGEN): | deps
|
||||
echo -e $(BUILD_MSG) "QR-Code-generator"
|
||||
+ cd vendor/QR-Code-generator/c && \
|
||||
$(MAKE)
|
||||
|
||||
nim_status_client: | $(DOTHERSIDE) $(STATUSGO) $(QRCODEGEN) deps
|
||||
echo -e $(BUILD_MSG) "$@" && \
|
||||
$(ENV_SCRIPT) nim c $(NIM_PARAMS) --passL:"$(STATUSGO)" --passL:"-lm" src/nim_status_client.nim
|
||||
$(ENV_SCRIPT) nim c $(NIM_PARAMS) --passL:"$(STATUSGO)" --passL:"$(QRCODEGEN)" --passL:"-lm" src/nim_status_client.nim
|
||||
|
||||
_APPIMAGE_TOOL := appimagetool-x86_64.AppImage
|
||||
APPIMAGE_TOOL := tmp/linux/tools/$(_APPIMAGE_TOOL)
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
import strformat
|
||||
import strutils
|
||||
import qrcodegen
|
||||
|
||||
proc generateQRCodeSVG*(text: string, border: int = 0): string =
|
||||
var qr0: array[0..qrcodegen_BUFFER_LEN_MAX, uint8]
|
||||
var tempBuffer: array[0..qrcodegen_BUFFER_LEN_MAX, uint8]
|
||||
let ok: bool = qrcodegen_encodeText(text, tempBuffer[0].addr, qr0[0].addr, qrcodegen_Ecc_MEDIUM, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true);
|
||||
if not ok:
|
||||
raise newException(Exception, "Error generating QR Code")
|
||||
else:
|
||||
var parts: seq[string] = @[]
|
||||
let size = qrcodegen_getSize(qr0[0].addr);
|
||||
for y in countup(0, size):
|
||||
for x in countup(0, size):
|
||||
if qrcodegen_getModule(qr0[0].addr, x.cint, y.cint):
|
||||
parts.add(&"M{x + border},{y + border}h1v1h-1z")
|
||||
let partsStr = parts.join(" ")
|
||||
result = &"<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\"><svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\" viewBox=\"0 0 {size + border * 2} {size + border * 2}\" stroke=\"none\"><rect width=\"100%\" height=\"100%\" fill=\"#FFFFFF\"/><path d=\"{partsStr}\" fill=\"#000000\"/></svg>"
|
||||
|
||||
|
|
@ -0,0 +1,164 @@
|
|||
##
|
||||
## QR Code generator library (C)
|
||||
##
|
||||
## Copyright (c) Project Nayuki. (MIT License)
|
||||
## https://www.nayuki.io/page/qr-code-generator-library
|
||||
##
|
||||
## Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
## this software and associated documentation files (the "Software"), to deal in
|
||||
## the Software without restriction, including without limitation the rights to
|
||||
## use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
## the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
## subject to the following conditions:
|
||||
## - The above copyright notice and this permission notice shall be included in
|
||||
## all copies or substantial portions of the Software.
|
||||
## - The Software is provided "as is", without warranty of any kind, express or
|
||||
## implied, including but not limited to the warranties of merchantability,
|
||||
## fitness for a particular purpose and noninfringement. In no event shall the
|
||||
## authors or copyright holders be liable for any claim, damages or other
|
||||
## liability, whether in an action of contract, tort or otherwise, arising from,
|
||||
## out of or in connection with the Software or the use or other dealings in the
|
||||
## Software.
|
||||
##
|
||||
|
||||
##
|
||||
## This library creates QR Code symbols, which is a type of two-dimension barcode.
|
||||
## Invented by Denso Wave and described in the ISO/IEC 18004 standard.
|
||||
## A QR Code structure is an immutable square grid of black and white cells.
|
||||
## The library provides functions to create a QR Code from text or binary data.
|
||||
## The library covers the QR Code Model 2 specification, supporting all versions (sizes)
|
||||
## from 1 to 40, all 4 error correction levels, and 4 character encoding modes.
|
||||
##
|
||||
## Ways to create a QR Code object:
|
||||
## - High level: Take the payload data and call qrcodegen_encodeText() or qrcodegen_encodeBinary().
|
||||
## - Low level: Custom-make the list of segments and call
|
||||
## qrcodegen_encodeSegments() or qrcodegen_encodeSegmentsAdvanced().
|
||||
## (Note that all ways require supplying the desired error correction level and various byte buffers.)
|
||||
##
|
||||
## ---- Enum and struct types----
|
||||
##
|
||||
## The error correction level in a QR Code symbol.
|
||||
##
|
||||
|
||||
type
|
||||
qrcodegen_Ecc* = enum ## Must be declared in ascending order of error protection
|
||||
## so that an internal qrcodegen function works properly
|
||||
qrcodegen_Ecc_LOW = 0, ## The QR Code can tolerate about 7% erroneous codewords
|
||||
qrcodegen_Ecc_MEDIUM, ## The QR Code can tolerate about 15% erroneous codewords
|
||||
qrcodegen_Ecc_QUARTILE, ## The QR Code can tolerate about 25% erroneous codewords
|
||||
qrcodegen_Ecc_HIGH ## The QR Code can tolerate about 30% erroneous codewords
|
||||
|
||||
|
||||
##
|
||||
## The mask pattern used in a QR Code symbol.
|
||||
##
|
||||
|
||||
type
|
||||
qrcodegen_Mask* = enum ## A special value to tell the QR Code encoder to
|
||||
## automatically select an appropriate mask pattern
|
||||
qrcodegen_Mask_AUTO = -1, ## The eight actual mask patterns
|
||||
qrcodegen_Mask_0 = 0, qrcodegen_Mask_1, qrcodegen_Mask_2, qrcodegen_Mask_3,
|
||||
qrcodegen_Mask_4, qrcodegen_Mask_5, qrcodegen_Mask_6, qrcodegen_Mask_7
|
||||
|
||||
|
||||
##
|
||||
## Describes how a segment's data bits are interpreted.
|
||||
##
|
||||
|
||||
type
|
||||
qrcodegen_Mode* = enum
|
||||
qrcodegen_Mode_NUMERIC = 0x00000001, qrcodegen_Mode_ALPHANUMERIC = 0x00000002,
|
||||
qrcodegen_Mode_BYTE = 0x00000004, qrcodegen_Mode_ECI = 0x00000007,
|
||||
qrcodegen_Mode_KANJI = 0x00000008
|
||||
|
||||
|
||||
##
|
||||
## A segment of character/binary/control data in a QR Code symbol.
|
||||
## The mid-level way to create a segment is to take the payload data
|
||||
## and call a factory function such as qrcodegen_makeNumeric().
|
||||
## The low-level way to create a segment is to custom-make the bit buffer
|
||||
## and initialize a qrcodegen_Segment struct with appropriate values.
|
||||
## Even in the most favorable conditions, a QR Code can only hold 7089 characters of data.
|
||||
## Any segment longer than this is meaningless for the purpose of generating QR Codes.
|
||||
## Moreover, the maximum allowed bit length is 32767 because
|
||||
## the largest QR Code (version 40) has 31329 modules.
|
||||
##
|
||||
|
||||
type
|
||||
qrcodegen_Segment* {.bycopy.} = object
|
||||
mode*: qrcodegen_Mode ## The mode indicator of this segment.
|
||||
## The length of this segment's unencoded data. Measured in characters for
|
||||
## numeric/alphanumeric/kanji mode, bytes for byte mode, and 0 for ECI mode.
|
||||
## Always zero or positive. Not the same as the data's bit length.
|
||||
numChars*: cint ## The data bits of this segment, packed in bitwise big endian.
|
||||
## Can be null if the bit length is zero.
|
||||
data*: ptr uint8 ## The number of valid data bits used in the buffer. Requires
|
||||
## 0 <= bitLength <= 32767, and bitLength <= (capacity of data array) * 8.
|
||||
## The character count (numChars) must agree with the mode and the bit buffer length.
|
||||
bitLength*: cint
|
||||
|
||||
|
||||
## ---- Macro constants and functions ----
|
||||
|
||||
const
|
||||
qrcodegen_VERSION_MIN* = 1
|
||||
qrcodegen_VERSION_MAX* = 40
|
||||
|
||||
## Calculates the number of bytes needed to store any QR Code up to and including the given version number,
|
||||
## as a compile-time constant. For example, 'uint8 buffer[qrcodegen_BUFFER_LEN_FOR_VERSION(25)];'
|
||||
## can store any single QR Code from version 1 to 25 (inclusive). The result fits in an int (or int16).
|
||||
## Requires qrcodegen_VERSION_MIN <= n <= qrcodegen_VERSION_MAX.
|
||||
|
||||
template qrcodegen_BUFFER_LEN_FOR_VERSION*(n: untyped): untyped =
|
||||
((((n) * 4 + 17) * ((n) * 4 + 17) + 7) div 8 + 1)
|
||||
|
||||
## The worst-case number of bytes needed to store one QR Code, up to and including
|
||||
## version 40. This value equals 3918, which is just under 4 kilobytes.
|
||||
## Use this more convenient value to avoid calculating tighter memory bounds for buffers.
|
||||
|
||||
const
|
||||
qrcodegen_BUFFER_LEN_MAX* = qrcodegen_BUFFER_LEN_FOR_VERSION(
|
||||
qrcodegen_VERSION_MAX)
|
||||
|
||||
## ---- Functions (high level) to generate QR Codes ----
|
||||
##
|
||||
## Encodes the given text string to a QR Code, returning true if encoding succeeded.
|
||||
## If the data is too long to fit in any version in the given range
|
||||
## at the given ECC level, then false is returned.
|
||||
## - The input text must be encoded in UTF-8 and contain no NULs.
|
||||
## - The variables ecl and mask must correspond to enum constant values.
|
||||
## - Requires 1 <= minVersion <= maxVersion <= 40.
|
||||
## - The arrays tempBuffer and qrcode must each have a length
|
||||
## of at least qrcodegen_BUFFER_LEN_FOR_VERSION(maxVersion).
|
||||
## - After the function returns, tempBuffer contains no useful data.
|
||||
## - If successful, the resulting QR Code may use numeric,
|
||||
## alphanumeric, or byte mode to encode the text.
|
||||
## - In the most optimistic case, a QR Code at version 40 with low ECC
|
||||
## can hold any UTF-8 string up to 2953 bytes, or any alphanumeric string
|
||||
## up to 4296 characters, or any digit string up to 7089 characters.
|
||||
## These numbers represent the hard upper limit of the QR Code standard.
|
||||
## - Please consult the QR Code specification for information on
|
||||
## data capacities per version, ECC level, and text encoding mode.
|
||||
##
|
||||
|
||||
proc qrcodegen_encodeText*(text: cstring; tempBuffer: ptr uint8;
|
||||
qrcode: ptr uint8; ecl: qrcodegen_Ecc; minVersion: cint;
|
||||
maxVersion: cint; mask: qrcodegen_Mask; boostEcl: bool): bool {.importc: "qrcodegen_encodeText".}
|
||||
|
||||
#proc qrcodegen_makeEci*(assignVal: clong; buf: ptr uint8): qrcodegen_Segment
|
||||
## ---- Functions to extract raw data from QR Codes ----
|
||||
##
|
||||
## Returns the side length of the given QR Code, assuming that encoding succeeded.
|
||||
## The result is in the range [21, 177]. Note that the length of the array buffer
|
||||
## is related to the side length - every 'uint8 qrcode[]' must have length at least
|
||||
## qrcodegen_BUFFER_LEN_FOR_VERSION(version), which equals ceil(size^2 / 8 + 1).
|
||||
##
|
||||
|
||||
proc qrcodegen_getSize*(qrcode: ptr uint8): cint {.importc: "qrcodegen_getSize".}
|
||||
##
|
||||
## Returns the color of the module (pixel) at the given coordinates, which is false
|
||||
## for white or true for black. The top left corner has the coordinates (x=0, y=0).
|
||||
## If the given coordinates are out of bounds, then false (white) is returned.
|
||||
##
|
||||
|
||||
proc qrcodegen_getModule*(qrcode: ptr uint8; x: cint; y: cint): bool {.importc: "qrcodegen_getModule".}
|
|
@ -6,6 +6,7 @@ import ../../status/contacts as status_contacts
|
|||
import ../../status/accounts as status_accounts
|
||||
import ../../status/status
|
||||
import ../../status/chat/chat
|
||||
import qrcode/qrcode
|
||||
|
||||
QtObject:
|
||||
type ProfileView* = ref object of QObject
|
||||
|
@ -93,3 +94,6 @@ QtObject:
|
|||
proc isAdded*(self: ProfileView, id: string): bool {.slot.} =
|
||||
if id == "": return false
|
||||
self.status.contacts.isAdded(id)
|
||||
|
||||
proc qrCode*(self: ProfileView, text:string): string {.slot.} =
|
||||
result = "data:image/svg+xml;utf8," & generateQRCodeSVG(text, 2)
|
||||
|
|
|
@ -10,8 +10,10 @@ ModalPopup {
|
|||
property var identicon: ""
|
||||
property var userName: ""
|
||||
property var fromAuthor: ""
|
||||
property bool showQR: false
|
||||
|
||||
function openPopup(userNameParam, fromAuthorParam, identiconParam) {
|
||||
this.showQR = false
|
||||
this.userName = userNameParam
|
||||
this.fromAuthor = fromAuthorParam
|
||||
this.identicon = identiconParam
|
||||
|
@ -64,113 +66,137 @@ ModalPopup {
|
|||
color: Theme.darkGrey
|
||||
}
|
||||
|
||||
// TODO(pascal): implement qrcode view
|
||||
// Rectangle {
|
||||
// id: qrCodeButton
|
||||
// height: 32
|
||||
// width: 32
|
||||
// anchors.top: parent.top
|
||||
// anchors.topMargin: Theme.padding
|
||||
// anchors.right: parent.right
|
||||
// anchors.rightMargin: 32 + Theme.smallPadding
|
||||
// radius: 8
|
||||
|
||||
// Image {
|
||||
// source: "../../../../shared/img/qr-code-icon.svg"
|
||||
// anchors.horizontalCenter: parent.horizontalCenter
|
||||
// anchors.verticalCenter: parent.verticalCenter
|
||||
// }
|
||||
Rectangle {
|
||||
id: qrCodeButton
|
||||
height: 32
|
||||
width: 32
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: Theme.padding
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 32 + Theme.smallPadding
|
||||
radius: 8
|
||||
|
||||
// MouseArea {
|
||||
// cursorShape: Qt.PointingHandCursor
|
||||
// anchors.fill: parent
|
||||
// hoverEnabled: true
|
||||
// onExited: {
|
||||
// qrCodeButton.color = Theme.white
|
||||
// }
|
||||
// onEntered:{
|
||||
// qrCodeButton.color = Theme.grey
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
Image {
|
||||
source: "../../../img/qr-code-icon.svg"
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
onExited: {
|
||||
qrCodeButton.color = Theme.white
|
||||
}
|
||||
onEntered:{
|
||||
qrCodeButton.color = Theme.grey
|
||||
}
|
||||
onClicked: {
|
||||
showQR = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: labelEnsUsername
|
||||
text: qsTr("ENS username")
|
||||
font.pixelSize: 13
|
||||
font.weight: Font.Medium
|
||||
color: Theme.darkGrey
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.smallPadding
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: Theme.smallPadding
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
visible: showQR
|
||||
Image {
|
||||
asynchronous: true
|
||||
fillMode: QtQuick.Image.PreserveAspectFit
|
||||
source: profileModel.qrCode(fromAuthor)
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
height: 212
|
||||
width: 212
|
||||
mipmap: true
|
||||
smooth: false
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: valueEnsName
|
||||
text: "@emily.stateofus.eth"
|
||||
font.pixelSize: 14
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.smallPadding
|
||||
anchors.top: labelEnsUsername.bottom
|
||||
anchors.topMargin: Theme.smallPadding
|
||||
}
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
visible: !showQR
|
||||
|
||||
StyledText {
|
||||
id: labelChatKey
|
||||
text: qsTr("Chat key")
|
||||
font.pixelSize: 13
|
||||
font.weight: Font.Medium
|
||||
color: Theme.darkGrey
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.smallPadding
|
||||
anchors.top: valueEnsName.bottom
|
||||
anchors.topMargin: Theme.padding
|
||||
}
|
||||
StyledText {
|
||||
id: labelEnsUsername
|
||||
text: qsTr("ENS username")
|
||||
font.pixelSize: 13
|
||||
font.weight: Font.Medium
|
||||
color: Theme.darkGrey
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.smallPadding
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: Theme.smallPadding
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: valueChatKey
|
||||
text: fromAuthor
|
||||
width: 160
|
||||
elide: Text.ElideMiddle
|
||||
font.pixelSize: 14
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.smallPadding
|
||||
anchors.top: labelChatKey.bottom
|
||||
anchors.topMargin: Theme.smallPadding
|
||||
}
|
||||
StyledText {
|
||||
id: valueEnsName
|
||||
text: "@emily.stateofus.eth"
|
||||
font.pixelSize: 14
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.smallPadding
|
||||
anchors.top: labelEnsUsername.bottom
|
||||
anchors.topMargin: Theme.smallPadding
|
||||
}
|
||||
|
||||
Separator {
|
||||
id: separator
|
||||
anchors.top: valueChatKey.bottom
|
||||
anchors.topMargin: Theme.padding
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: -Theme.padding
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: -Theme.padding
|
||||
}
|
||||
StyledText {
|
||||
id: labelChatKey
|
||||
text: qsTr("Chat key")
|
||||
font.pixelSize: 13
|
||||
font.weight: Font.Medium
|
||||
color: Theme.darkGrey
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.smallPadding
|
||||
anchors.top: valueEnsName.bottom
|
||||
anchors.topMargin: Theme.padding
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: labelShareURL
|
||||
text: qsTr("Share Profile URL")
|
||||
font.pixelSize: 13
|
||||
font.weight: Font.Medium
|
||||
color: Theme.darkGrey
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.smallPadding
|
||||
anchors.top: separator.bottom
|
||||
anchors.topMargin: Theme.padding
|
||||
}
|
||||
StyledText {
|
||||
id: valueChatKey
|
||||
text: fromAuthor
|
||||
width: 160
|
||||
elide: Text.ElideMiddle
|
||||
font.pixelSize: 14
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.smallPadding
|
||||
anchors.top: labelChatKey.bottom
|
||||
anchors.topMargin: Theme.smallPadding
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: valueShareURL
|
||||
text: "https://join.status.im/u/" + fromAuthor.substr(0, 4) + "..." + fromAuthor.substr(fromAuthor.length - 5)
|
||||
font.pixelSize: 14
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.smallPadding
|
||||
anchors.top: labelShareURL.bottom
|
||||
anchors.topMargin: Theme.smallPadding
|
||||
Separator {
|
||||
id: separator
|
||||
anchors.top: valueChatKey.bottom
|
||||
anchors.topMargin: Theme.padding
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: -Theme.padding
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: -Theme.padding
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: labelShareURL
|
||||
text: qsTr("Share Profile URL")
|
||||
font.pixelSize: 13
|
||||
font.weight: Font.Medium
|
||||
color: Theme.darkGrey
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.smallPadding
|
||||
anchors.top: separator.bottom
|
||||
anchors.topMargin: Theme.padding
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: valueShareURL
|
||||
text: "https://join.status.im/u/" + fromAuthor.substr(0, 4) + "..." + fromAuthor.substr(fromAuthor.length - 5)
|
||||
font.pixelSize: 14
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.smallPadding
|
||||
anchors.top: labelShareURL.bottom
|
||||
anchors.topMargin: Theme.smallPadding
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(pascal): implement copy to clipboard component
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
<svg width="22" height="22" viewBox="0 0 22 22" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M3.66659 1.83325C2.65406 1.83325 1.83325 2.65406 1.83325 3.66659V8.24992C1.83325 9.26244 2.65406 10.0833 3.66659 10.0833H8.24992C9.26244 10.0833 10.0833 9.26244 10.0833 8.24992V3.66659C10.0833 2.65406 9.26244 1.83325 8.24992 1.83325H3.66659ZM8.24992 3.20825H3.66659C3.41345 3.20825 3.20825 3.41345 3.20825 3.66659V8.24992C3.20825 8.50305 3.41345 8.70825 3.66659 8.70825H8.24992C8.50305 8.70825 8.70825 8.50305 8.70825 8.24992V3.66659C8.70825 3.41345 8.50305 3.20825 8.24992 3.20825Z" fill="black"/>
|
||||
<path d="M5.95825 14.6666C5.19886 14.6666 4.58325 15.2822 4.58325 16.0416C4.58325 16.801 5.19886 17.4166 5.95825 17.4166C6.71764 17.4166 7.33325 16.801 7.33325 16.0416C7.33325 15.2822 6.71764 14.6666 5.95825 14.6666Z" fill="black"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M5.95825 11.9166C3.68008 11.9166 1.83325 13.7634 1.83325 16.0416C1.83325 18.3198 3.68008 20.1666 5.95825 20.1666C8.23643 20.1666 10.0833 18.3198 10.0833 16.0416C10.0833 13.7634 8.23643 11.9166 5.95825 11.9166ZM3.20825 16.0416C3.20825 17.5604 4.43947 18.7916 5.95825 18.7916C7.47704 18.7916 8.70825 17.5604 8.70825 16.0416C8.70825 14.5228 7.47704 13.2916 5.95825 13.2916C4.43947 13.2916 3.20825 14.5228 3.20825 16.0416Z" fill="black"/>
|
||||
<path d="M12.8333 11.9166C12.327 11.9166 11.9166 12.327 11.9166 12.8333V14.2083C11.9166 14.7145 12.327 15.1249 12.8333 15.1249H14.2083C14.7145 15.1249 15.1249 14.7145 15.1249 14.2083V12.8333C15.1249 12.327 14.7145 11.9166 14.2083 11.9166H12.8333Z" fill="black"/>
|
||||
<path d="M16.9583 12.8333C16.9583 12.327 17.3687 11.9166 17.8749 11.9166H19.2499C19.7562 11.9166 20.1666 12.327 20.1666 12.8333V14.2083C20.1666 14.7145 19.7562 15.1249 19.2499 15.1249H17.8749C17.3687 15.1249 16.9583 14.7145 16.9583 14.2083V12.8333Z" fill="black"/>
|
||||
<path d="M17.8749 16.9583C17.3687 16.9583 16.9583 17.3687 16.9583 17.8749V19.2499C16.9583 19.7562 17.3687 20.1666 17.8749 20.1666H19.2499C19.7562 20.1666 20.1666 19.7562 20.1666 19.2499V17.8749C20.1666 17.3687 19.7562 16.9583 19.2499 16.9583H17.8749Z" fill="black"/>
|
||||
<path d="M11.9166 17.8749C11.9166 17.3687 12.327 16.9583 12.8333 16.9583H14.2083C14.7145 16.9583 15.1249 17.3687 15.1249 17.8749V19.2499C15.1249 19.7562 14.7145 20.1666 14.2083 20.1666H12.8333C12.327 20.1666 11.9166 19.7562 11.9166 19.2499V17.8749Z" fill="black"/>
|
||||
<path d="M14.6666 5.49992C14.6666 4.99366 15.077 4.58325 15.5833 4.58325H16.4999C17.0062 4.58325 17.4166 4.99366 17.4166 5.49992V6.41659C17.4166 6.92285 17.0062 7.33325 16.4999 7.33325H15.5833C15.077 7.33325 14.6666 6.92285 14.6666 6.41659V5.49992Z" fill="black"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.9166 3.66659C11.9166 2.65406 12.7374 1.83325 13.7499 1.83325H18.3333C19.3458 1.83325 20.1666 2.65406 20.1666 3.66659V8.24992C20.1666 9.26244 19.3458 10.0833 18.3333 10.0833H13.7499C12.7374 10.0833 11.9166 9.26244 11.9166 8.24992V3.66659ZM13.7499 3.20825H18.3333C18.5864 3.20825 18.7916 3.41345 18.7916 3.66659V8.24992C18.7916 8.50305 18.5864 8.70825 18.3333 8.70825H13.7499C13.4968 8.70825 13.2916 8.50305 13.2916 8.24992V3.66659C13.2916 3.41345 13.4968 3.20825 13.7499 3.20825Z" fill="black"/>
|
||||
</svg>
|
After Width: | Height: | Size: 3.2 KiB |
|
@ -0,0 +1 @@
|
|||
Subproject commit 6d8cc8bee9ca0f14985ca3b8564f5e2f86a8faec
|
Loading…
Reference in New Issue