Add login page and forget room system

This commit is contained in:
miruka 2019-04-26 16:02:20 -04:00
parent 34d2bd233d
commit 5988eccdbb
39 changed files with 490 additions and 101 deletions

View File

@ -1,33 +0,0 @@
# harmonyqml
[![PyPI downloads](http://pepy.tech/badge/harmonyqml)](
http://pepy.tech/project/harmonyqml)
[![PyPI version](https://img.shields.io/pypi/v/harmonyqml.svg)](
https://pypi.org/projects/harmonyqml)
[![PyPI pyversions](https://img.shields.io/pypi/pyversions/harmonyqml.svg)](
https://pypi.python.org/pypi/harmonyqml)
<SHORTDESC>
## CLI examples
```sh
$ harmonyqml
```
## Python package examples
```python3
>>> import harmonyqml
>>>
```
## Installation
Requires Python 3.6+, tested on GNU/Linux only.
```sh
# pip3 install harmonyqml
```

19
TODO.md
View File

@ -1,5 +1,6 @@
- Current focus
- Merge login page
- Just import nio?
- Refactoring
- Migrate more JS functions to their own files / Implement in Python instead
@ -13,6 +14,8 @@
- Bug when resizing window being tiled (i3), can't figure it out
- UI
- Leave room
- Forget room warning popup
- Use HRowLayout and its totalSpacing wherever possible
- Spacer component
- One line label componant
@ -34,6 +37,8 @@
- Status message and presence
- Client improvements
- HTTP/2
- `retry_after_ms` when rate-limited
- Direct chats category
- On sync, check messages API, if a limited sync timeline was received
- Markdown: don't turn #things into title (space), disable __ syntax
@ -46,11 +51,21 @@
- When inviting someone to direct chat, room is "Empty room" until accepted,
it should be the peer's display name instead.
- Keep an accounts order
- See `Qt.callLater()` potential usages
- Banner name color instead of bold
- Missing nio support
- Forget room
- Left room events
- `org.matrix.room.preview_urls` event
- `m.room.aliases` event
- Avatars
- Support "Empty room (was ...)" after peer left
- Waiting for approval/release
- nio avatars
- olm/olm-devel 0.3.1 in void repos
- html-sanitizer allowed attributes fix pypi release
- Distribution
- Review setup.py, add dependencies
- REAMDE.md
- Remove initial test room switch

View File

@ -26,6 +26,8 @@ class Client(QObject):
roomJoined = pyqtSignal(str)
roomLeft = pyqtSignal([str, dict], [str])
roomAboutToBeForgotten = pyqtSignal(str)
roomSyncPrevBatchTokenReceived = pyqtSignal(str, str)
roomPastPrevBatchTokenReceived = pyqtSignal(str, str)
roomEventReceived = pyqtSignal(str, str, dict)
@ -259,4 +261,5 @@ class Client(QObject):
@pyqtSlot(str)
@futurize()
def forgetRoom(self, room_id: str) -> None:
raise NotImplementedError()
self.roomAboutToBeForgotten.emit(room_id)
return self.net.talk(self.nio.room_forget, room_id=room_id)

View File

@ -25,7 +25,7 @@ _CONFIG_LOCK = threading.Lock()
class ClientManager(QObject):
clientAdded = pyqtSignal(Client)
clientDeleted = pyqtSignal(str)
_clientsUpdate = pyqtSignal()
clientCountChanged = pyqtSignal(int)
def __init__(self, backend: Backend) -> None:
@ -33,19 +33,25 @@ class ClientManager(QObject):
self.backend = backend
self._clients: Dict[str, Client] = {}
self.clientAdded.connect(self._clientsUpdate.emit)
self.clientDeleted.connect(self._clientsUpdate.emit)
func = lambda: self.clientCountChanged.emit(len(self.clients))
self.clientAdded.connect(func)
self.clientDeleted.connect(func)
def __repr__(self) -> str:
return f"{type(self).__name__}(clients={self.clients!r})"
@pyqtProperty("QVariantMap", notify=_clientsUpdate)
@pyqtProperty("QVariantMap", notify=clientCountChanged)
def clients(self):
return self._clients
@pyqtProperty(int, notify=clientCountChanged)
def clientCount(self):
return len(self.clients)
@pyqtSlot()
def configLoad(self) -> None:
for user_id, info in self.configAccounts().items():

View File

@ -114,6 +114,7 @@ class NetworkManager:
nio_func: NioRequestFunc,
*args,
**kwargs) -> nr.Response:
with self._lock:
retry = RetrySleeper()

View File

@ -268,3 +268,11 @@ class SignalManager(QObject):
self._events_in_transfer += 1
self._move_room(client.userId, room_id)
def onRoomAboutToBeForgotten(self, client: Client, room_id: str) -> None:
with self._lock:
rooms = self.backend.models.rooms[client.userId]
del rooms[rooms.indexWhere("roomId", room_id)]
self.backend.models.roomEvents[room_id].clear()

View File

@ -9,7 +9,8 @@ ApplicationWindow {
Loader {
anchors.fill: parent
source: "UI.qml"
source: Backend.clientManager.clientCount < 1 ?
"pages/LoginPage.qml" : "pages/MainUI.qml"
objectName: "UILoader"
}
}

View File

@ -3,9 +3,73 @@ import QtQuick.Controls 2.2
import QtQuick.Layouts 1.4
Button {
property alias fontSize: buttonLabel.font.pixelSize
property color backgroundColor: "lightgray"
property alias overlayOpacity: buttonBackgroundOverlay.opacity
property string iconName: ""
property bool circle: false
id: button
display: Button.TextBesideIcon
icon.source: "../../icons/" + iconName + ".svg"
background: Rectangle {
id: buttonBackground
color: Qt.lighter(backgroundColor, checked ? 1.3 : 1.0)
radius: circle ? height : 0
Rectangle {
id: buttonBackgroundOverlay
anchors.fill: parent
radius: parent.radius
color: "black"
opacity: 0
}
}
contentItem: HRowLayout {
spacing: button.text && iconName ? 5 : 0
Component {
id: buttonIcon
Image {
cache: true
mipmap: true
source: "../../icons/" + iconName + ".svg"
fillMode: Image.PreserveAspectFit
width: button.text ? 20 : 24
height: width
}
}
Loader {
sourceComponent: iconName ? buttonIcon : undefined
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
HLabel {
id: buttonLabel
text: button.text
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight
maximumLineCount: 1
Layout.maximumWidth: button.width - buttonIcon.width
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
}
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
propagateComposedEvents: true
onEntered: overlayOpacity = checked ? 0 : 0.3
onExited: overlayOpacity = 0
onPressed: overlayOpacity += 0.3
onReleased: {
if (checkable) { checked = ! checked }
overlayOpacity = checked ? 0 : 0.3
}
}
}

View File

@ -1,12 +1,9 @@
import QtQuick 2.7
import QtQuick.Controls 2.0
import "."
Label {
property int bigSize: 24
property int normalSize: 16
property int smallSize: 12
font.family: "Roboto"
font.pixelSize: normalSize
font.family: HStyle.fontFamily.sans
font.pixelSize: HStyle.fontSize.normal
textFormat: Text.PlainText
}

View File

@ -0,0 +1,22 @@
pragma Singleton
import QtQuick 2.7
QtObject {
readonly property int foo: 3
readonly property QtObject fontSize: QtObject {
readonly property int smallest: 6
readonly property int smaller: 8
readonly property int small: 12
readonly property int normal: 16
readonly property int big: 24
readonly property int bigger: 32
readonly property int biggest: 48
}
readonly property QtObject fontFamily: QtObject {
readonly property string sans: "Roboto"
readonly property string serif: "Roboto Slab"
readonly property string mono: "Hack"
}
}

View File

@ -0,0 +1,9 @@
import QtQuick 2.7
import QtQuick.Controls 2.0
TextField {
font.family: HStyle.fontFamily.sans
font.pixelSize: HStyle.fontSize.normal
selectByMouse: true
}

View File

@ -0,0 +1 @@
singleton HStyle 1.0 HStyle.qml

View File

@ -9,6 +9,8 @@ Rectangle {
Layout.preferredHeight: 32
color: "#BBB"
signal buttonClicked(string signalId)
property alias avatarName: bannerAvatar.name
property alias avatarSource: bannerAvatar.imageSource
property alias labelText: bannerLabel.text
@ -77,8 +79,6 @@ Rectangle {
text: modelData.text
iconName: modelData.iconName
icon.color: modelData.iconColor
icon.width: 32
display: bannerButtons.displayMode
onClicked: {
@ -87,14 +87,20 @@ Rectangle {
iconName = "hourglass"
alreadyClicked = true
// modelData might become undefined after Backend call
var signalId = modelData.signalId
var iconName_ = modelData.iconName
var future =
Backend.clientManager.clients[chatPage.userId].
call(modelData.clientFunction,
modelData.clientArgs)
future.onGotResult.connect(
function() { iconName = modelData.iconName }
)
future.onGotResult.connect(function() {
iconName = iconName_
})
if (signalId) { buttonClicked(signalId) }
}
Layout.maximumWidth: bannerButtons.compact ? height : -1

View File

@ -16,6 +16,6 @@ Base.HLabel {
text: dateTime.toLocaleDateString() + (isToday ? qsTr(" (Today)") : "")
horizontalAlignment: Text.AlignHCenter
font.pixelSize: normalSize * 1.1
font.pixelSize: Base.HStyle.fontSize.big
color: "darkolivegreen"
}

View File

@ -27,7 +27,8 @@ RowLayout {
(displayName.value || dict.sender) +
(contentText.startsWith("'s ") ? "" : " ") +
contentText +
"&nbsp;&nbsp;<font size=" + smallSize + "px color='gray'>" +
"&nbsp;&nbsp;<font size=" + Base.HStyle.fontSize.small +
"px color='gray'>" +
Qt.formatDateTime(dateTime, "hh:mm:ss") +
"</font></font>"
textFormat: Text.RichText

View File

@ -17,15 +17,15 @@ Banner {
buttonModel: [
{
text: "Accept",
iconName: "accept",
iconColor: Qt.hsla(0.45, 0.9, 0.3, 1),
iconName: "invite_accept",
//iconColor: Qt.hsla(0.45, 0.9, 0.3, 1),
clientFunction: "joinRoom",
clientArgs: [chatPage.roomId],
},
{
text: "Decline",
iconName: "decline",
iconColor: Qt.hsla(0.95, 0.9, 0.35, 1),
iconName: "invite_decline",
//iconColor: Qt.hsla(0.95, 0.9, 0.35, 1),
clientFunction: "leaveRoom",
clientArgs: [chatPage.roomId],
}

View File

@ -7,14 +7,20 @@ import "utils.js" as ChatJS
Banner {
property var leftEvent: null
onButtonClicked: if (signalId === "forget") {
chatPage.canLoadPastEvents = false
pageStack.clear()
}
avatarName: ChatJS.getLeftBannerAvatarName(leftEvent, chatPage.userId)
labelText: ChatJS.getLeftBannerText(leftEvent)
buttonModel: [
{
signalId: "forget",
text: "Forget",
iconName: "trash_can",
iconColor: Qt.hsla(0.95, 0.9, 0.35, 1),
iconName: "forget_room",
//iconColor: Qt.hsla(0.95, 0.9, 0.35, 1),
clientFunction: "forgetRoom",
clientArgs: [chatPage.roomId],
}

View File

@ -35,11 +35,13 @@ Row {
text: (dict.formatted_body ?
Backend.htmlFilter.filter(dict.formatted_body) :
dict.body) +
"&nbsp;&nbsp;<font size=" + smallSize + "px color=gray>" +
"&nbsp;&nbsp;<font size=" + Base.HStyle.fontSize.small +
"px color=gray>" +
Qt.formatDateTime(dateTime, "hh:mm:ss") +
"</font>" +
(isLocalEcho ?
"&nbsp;<font size=" + smallSize + "px>⏳</font>" : "")
"&nbsp;<font size=" + Base.HStyle.fontSize.small +
"px>⏳</font>" : "")
textFormat: Text.RichText
background: Rectangle {color: "#DDD"}
wrapMode: Text.Wrap

View File

@ -4,6 +4,7 @@ import QtQuick.Layouts 1.4
import "../base" as Base
Rectangle {
property bool canLoadPastEvents: true
property int space: 8
Layout.fillWidth: true
@ -30,7 +31,7 @@ Rectangle {
property real yPos: visibleArea.yPosition
onYPosChanged: {
if (yPos <= 0.1) {
if (chatPage.canLoadPastEvents && yPos <= 0.1) {
Backend.loadPastEvents(chatPage.roomId)
}
}

View File

@ -28,7 +28,7 @@ Rectangle {
Base.HLabel {
id: roomName
text: displayName
font.pixelSize: bigSize
font.pixelSize: Base.HStyle.fontSize.big
elide: Text.ElideRight
maximumLineCount: 1
Layout.maximumWidth:
@ -39,7 +39,7 @@ Rectangle {
Base.HLabel {
id: roomTopic
text: topic
font.pixelSize: smallSize
font.pixelSize: Base.HStyle.fontSize.small
elide: Text.ElideRight
maximumLineCount: 1
Layout.maximumWidth:

View File

@ -9,6 +9,8 @@ ColumnLayout {
readonly property var roomInfo:
Backend.models.rooms.get(userId).getWhere("roomId", roomId)
property bool canLoadPastEvents: true
Component.onCompleted: console.log("replaced")

View File

@ -1,9 +0,0 @@
import QtQuick 2.7
import "../base" as Base
Rectangle {
Base.HLabel {
anchors.centerIn: parent
text: "Add account page"
}
}

View File

@ -1,9 +0,0 @@
import QtQuick 2.7
import "../base" as Base
Rectangle {
Base.HLabel {
anchors.centerIn: parent
text: "Add room page"
}
}

View File

@ -0,0 +1,122 @@
import QtQuick 2.7
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.4
import "../base" as Base
Image {
id: loginBackground
asynchronous: true
fillMode: Image.PreserveAspectCrop
cache: false
source: "../../images/login_background.jpg"
Rectangle {
color: Qt.hsla(1, 1, 1, 0.3)
id: loginBox
property real widthForHeight: 0.75
property int baseHeight: 300
property int baseWidth: baseHeight * widthForHeight
property int startScalingUpAboveHeight: 1080
anchors.centerIn: parent
height: Math.min(parent.height, baseHeight)
width: Math.min(parent.width, baseWidth)
scale: Math.max(1, parent.height / startScalingUpAboveHeight)
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
ColumnLayout {
anchors.fill: parent
id: mainColumn
property int hMargin: loginBox.baseWidth * 0.05
property int vMargin: hMargin * loginBox.widthForHeight
Base.HRowLayout {
Layout.alignment: Qt.AlignHCenter
Layout.margins: mainColumn.hMargin
Layout.topMargin: mainColumn.vMargin
Layout.bottomMargin: mainColumn.vMargin
Base.HLabel {
text: "Sign in"
font.pixelSize: Base.HStyle.fontSize.big
}
}
Item { Layout.fillHeight: true }
Base.HRowLayout {
Layout.margins: mainColumn.hMargin
Layout.topMargin: mainColumn.vMargin
Layout.bottomMargin: mainColumn.vMargin
Layout.alignment: Qt.AlignHCenter
spacing: mainColumn.hMargin * 1.25
Base.HButton {
id: loginWithUsernameButton
iconName: "username"
circle: true
checked: true
checkable: true
autoExclusive: true
}
Base.HButton {
id: loginWithEmailButton
iconName: "email"
circle: true
checkable: true
autoExclusive: true
}
Base.HButton {
id: loginWithPhoneButton
iconName: "phone"
circle: true
checkable: true
autoExclusive: true
}
}
Base.HTextField {
placeholderText: qsTr(
loginWithEmailButton.checked ? "Email" :
loginWithPhoneButton.checked ? "Phone" :
"Username"
)
Layout.fillWidth: true
Layout.margins: mainColumn.hMargin
Layout.topMargin: mainColumn.vMargin
Layout.bottomMargin: mainColumn.vMargin
}
Base.HTextField {
placeholderText: qsTr("Password")
Layout.fillWidth: true
Layout.margins: mainColumn.hMargin
Layout.topMargin: mainColumn.vMargin
Layout.bottomMargin: mainColumn.vMargin
}
Item { Layout.fillHeight: true }
Base.HRowLayout {
Base.HButton {
text: qsTr("Register")
Layout.fillWidth: true
}
Base.HButton {
text: qsTr("Login")
Layout.fillWidth: true
}
Base.HButton {
text: qsTr("Forgot?")
Layout.fillWidth: true
}
}
}
}
}

View File

@ -2,8 +2,8 @@ import QtQuick 2.7
import QtQuick.Controls 1.4 as Controls1
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.4
import "sidePane" as SidePane
import "chat" as Chat
import "../sidePane" as SidePane
import "../chat" as Chat
//https://doc.qt.io/qt-5/qml-qtquick-controls-splitview.html
Controls1.SplitView {
@ -17,13 +17,15 @@ Controls1.SplitView {
StackView {
function showRoom(userId, roomId) {
pageStack.replace(
"chat/Root.qml", { userId: userId, roomId: roomId }
"../chat/Root.qml", { userId: userId, roomId: roomId }
)
}
id: pageStack
onCurrentItemChanged: currentItem.forceActiveFocus()
onCurrentItemChanged: if (currentItem) {
currentItem.forceActiveFocus()
}
initialItem: Item { // TODO: (test, remove)
Keys.onEnterPressed: pageStack.showRoom(

View File

@ -1,9 +0,0 @@
import QtQuick 2.7
import "../base" as Base
Rectangle {
Base.HLabel {
anchors.centerIn: parent
text: "Settings page"
}
}

View File

@ -52,7 +52,7 @@ MouseArea {
text: getText()
textFormat: Text.StyledText
font.pixelSize: smallSize
font.pixelSize: Base.HStyle.fontSize.small
elide: Text.ElideRight
maximumLineCount: 1
Layout.maximumWidth: roomLabel.Layout.maximumWidth

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M9 21.035l-9-8.638 2.791-2.87 6.156 5.874 12.21-12.436 2.843 2.817z"/></svg>

Before

Width:  |  Height:  |  Size: 168 B

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M23 20.168l-8.185-8.187 8.185-8.174-2.832-2.807-8.182 8.179-8.176-8.179-2.81 2.81 8.186 8.196-8.186 8.184 2.81 2.81 8.203-8.192 8.18 8.192z"/></svg>

Before

Width:  |  Height:  |  Size: 240 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M12 12.713l-11.985-9.713h23.971l-11.986 9.713zm-5.425-1.822l-6.575-5.329v12.501l6.575-7.172zm10.85 0l6.575 7.172v-12.501l-6.575 5.329zm-1.557 1.261l-3.868 3.135-3.868-3.135-8.11 8.848h23.956l-8.11-8.848z"/></svg>

After

Width:  |  Height:  |  Size: 304 B

View File

@ -0,0 +1,51 @@
<?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="24"
height="24"
viewBox="0 0 24 24"
version="1.1"
id="svg4"
sodipodi:docname="forget_room.svg"
inkscape:version="">
<metadata
id="metadata10">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs8" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="640"
inkscape:window-height="480"
id="namedview6"
showgrid="false"
inkscape:zoom="9.8333333"
inkscape:cx="0.81355932"
inkscape:cy="12.610169"
inkscape:current-layer="svg4" />
<path
d="M3 6v18h18v-18h-18zm5 14c0 .552-.448 1-1 1s-1-.448-1-1v-10c0-.552.448-1 1-1s1 .448 1 1v10zm5 0c0 .552-.448 1-1 1s-1-.448-1-1v-10c0-.552.448-1 1-1s1 .448 1 1v10zm5 0c0 .552-.448 1-1 1s-1-.448-1-1v-10c0-.552.448-1 1-1s1 .448 1 1v10zm4-18v2h-20v-2h5.711c.9 0 1.631-1.099 1.631-2h5.315c0 .901.73 2 1.631 2h5.712z"
id="path2"
style="fill:#ab0937;fill-opacity:1" />
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@ -0,0 +1,51 @@
<?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="24"
height="24"
viewBox="0 0 24 24"
version="1.1"
id="svg4"
sodipodi:docname="invite_accept.svg"
inkscape:version="">
<metadata
id="metadata10">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs8" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="640"
inkscape:window-height="480"
id="namedview6"
showgrid="false"
inkscape:zoom="9.8333333"
inkscape:cx="-28.271186"
inkscape:cy="12"
inkscape:current-layer="svg4" />
<path
d="M9 21.035l-9-8.638 2.791-2.87 6.156 5.874 12.21-12.436 2.843 2.817z"
id="path2"
style="fill:#0d8967;fill-opacity:1" />
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,51 @@
<?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="24"
height="24"
viewBox="0 0 24 24"
version="1.1"
id="svg14"
sodipodi:docname="invite_decline.svg"
inkscape:version="">
<metadata
id="metadata20">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs18" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="640"
inkscape:window-height="480"
id="namedview16"
showgrid="false"
inkscape:zoom="9.8333333"
inkscape:cx="6.9152542"
inkscape:cy="17.084746"
inkscape:current-layer="svg14" />
<path
d="M23 20.168l-8.185-8.187 8.185-8.174-2.832-2.807-8.182 8.179-8.176-8.179-2.81 2.81 8.186 8.196-8.186 8.184 2.81 2.81 8.203-8.192 8.18 8.192z"
id="path12"
style="fill:#ab0938;fill-opacity:1" />
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M18.48 22.926l-1.193.658c-6.979 3.621-19.082-17.494-12.279-21.484l1.145-.637 3.714 6.467-1.139.632c-2.067 1.245 2.76 9.707 4.879 8.545l1.162-.642 3.711 6.461zm-9.808-22.926l-1.68.975 3.714 6.466 1.681-.975-3.715-6.466zm8.613 14.997l-1.68.975 3.714 6.467 1.681-.975-3.715-6.467z"/></svg>

After

Width:  |  Height:  |  Size: 378 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M12 2c5.514 0 10 4.486 10 10s-4.486 10-10 10-10-4.486-10-10 4.486-10 10-10zm0-2c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12z"/></svg>

After

Width:  |  Height:  |  Size: 250 B

View File

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M3 6v18h18v-18h-18zm5 14c0 .552-.448 1-1 1s-1-.448-1-1v-10c0-.552.448-1 1-1s1 .448 1 1v10zm5 0c0 .552-.448 1-1 1s-1-.448-1-1v-10c0-.552.448-1 1-1s1 .448 1 1v10zm5 0c0 .552-.448 1-1 1s-1-.448-1-1v-10c0-.552.448-1 1-1s1 .448 1 1v10zm4-18v2h-20v-2h5.711c.9 0 1.631-1.099 1.631-2h5.315c0 .901.73 2 1.631 2h5.712z"/></svg>

Before

Width:  |  Height:  |  Size: 409 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M20.822 18.096c-3.439-.794-6.64-1.49-5.09-4.418 4.72-8.912 1.251-13.678-3.732-13.678-5.082 0-8.464 4.949-3.732 13.678 1.597 2.945-1.725 3.641-5.09 4.418-3.073.71-3.188 2.236-3.178 4.904l.004 1h23.99l.004-.969c.012-2.688-.092-4.222-3.176-4.935z"/></svg>

After

Width:  |  Height:  |  Size: 344 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
version="1.1"
width="793.322"
height="340.809"
style="paint-order:stroke;stroke:#ffffff;stroke-opacity:0.5;stroke-width:4;stroke-linejoin:round"
id="Layer_1">
<path
d="m 10.875,9.711 v 321.386 h 23.13 v 7.711 H 2 V 2 h 32 v 7.71 z" />
<path
d="m 100,111.595 v 16.264 h 0.463 c 4.338,-6.191 9.563,-11 15.684,-14.406 6.117,-3.402 13.129,-5.11 21.027,-5.11 7.588,0 14.521,1.475 20.793,4.415 6.274,2.945 11.038,8.131 14.291,15.567 3.56,-5.265 8.4,-9.913 14.521,-13.94 6.117,-4.025 13.358,-6.042 21.724,-6.042 6.351,0 12.234,0.776 17.66,2.325 5.418,1.549 10.065,4.027 13.938,7.434 3.869,3.41 6.889,7.863 9.062,13.357 2.167,5.504 3.253,12.122 3.253,19.869 v 80.385 H 219.41 v -68.074 c 0,-4.025 -0.154,-7.82 -0.465,-11.385 -0.313,-3.56 -1.161,-6.656 -2.555,-9.293 -1.395,-2.631 -3.45,-4.724 -6.157,-6.274 -2.711,-1.543 -6.391,-2.322 -11.037,-2.322 -4.646,0 -8.403,0.896 -11.269,2.671 -2.868,1.784 -5.112,4.109 -6.737,6.971 -1.626,2.869 -2.711,6.12 -3.252,9.762 -0.545,3.638 -0.814,7.318 -0.814,11.035 v 66.91 h -33 v -67.375 c 0,-3.562 -0.081,-7.087 -0.23,-10.57 -0.158,-3.487 -0.814,-6.7 -1.978,-9.645 -1.162,-2.94 -3.1,-5.304 -5.809,-7.088 -2.711,-1.775 -6.7,-2.671 -11.965,-2.671 -1.551,0 -3.603,0.349 -6.156,1.048 -2.556,0.697 -5.036,2.016 -7.435,3.949 -2.404,1.938 -4.454,4.726 -6.158,8.363 -1.705,3.642 -2.556,8.402 -2.556,14.287 v 69.701 H 68.856 V 111.595 Z" />
<path
d="m 273.544,129.255 c 3.405,-5.113 7.744,-9.215 13.012,-12.316 5.264,-3.097 11.186,-5.303 17.771,-6.621 6.582,-1.315 13.205,-1.976 19.865,-1.976 6.042,0 12.158,0.428 18.354,1.277 6.195,0.855 11.85,2.522 16.962,5 5.111,2.477 9.292,5.926 12.546,10.338 3.253,4.414 4.879,10.262 4.879,17.543 v 62.494 c 0,5.428 0.31,10.611 0.931,15.567 0.615,4.959 1.701,8.676 3.251,11.153 H 347.66 c -0.621,-1.86 -1.126,-3.755 -1.511,-5.693 -0.39,-1.933 -0.661,-3.908 -0.813,-5.923 -5.267,5.422 -11.465,9.217 -18.585,11.386 -7.127,2.163 -14.407,3.251 -21.842,3.251 -5.733,0 -11.077,-0.698 -16.033,-2.09 -4.958,-1.395 -9.293,-3.562 -13.01,-6.51 -3.718,-2.938 -6.622,-6.656 -8.713,-11.147 -2.091,-4.491 -3.138,-9.84 -3.138,-16.033 0,-6.813 1.2,-12.43 3.604,-16.84 2.4,-4.417 5.495,-7.939 9.295,-10.575 3.793,-2.632 8.129,-4.607 13.01,-5.923 4.878,-1.315 9.795,-2.358 14.752,-3.137 4.957,-0.772 9.835,-1.393 14.638,-1.857 4.801,-0.466 9.062,-1.164 12.779,-2.093 3.718,-0.929 6.658,-2.282 8.829,-4.065 2.165,-1.781 3.172,-4.375 3.02,-7.785 0,-3.56 -0.58,-6.389 -1.742,-8.479 -1.161,-2.09 -2.711,-3.719 -4.646,-4.88 -1.937,-1.161 -4.183,-1.936 -6.737,-2.325 -2.557,-0.382 -5.309,-0.58 -8.248,-0.58 -6.506,0 -11.617,1.395 -15.335,4.183 -3.716,2.788 -5.889,7.437 -6.506,13.94 h -33 c 0.462,-7.742 2.395,-14.173 5.807,-19.281 z m 65.169,46.583 c -2.09,0.696 -4.337,1.275 -6.736,1.741 -2.402,0.465 -4.918,0.853 -7.551,1.161 -2.635,0.313 -5.268,0.698 -7.7,1.163 -2.48,0.461 -4.919,1.086 -7.317,1.857 -2.404,0.779 -4.495,1.822 -6.274,3.138 -1.784,1.317 -3.216,2.985 -4.3,5 -1.085,2.014 -1.626,4.571 -1.626,7.668 0,2.94 0.541,5.422 1.626,7.431 1.084,2.017 2.558,3.604 4.416,4.765 1.858,1.161 4.025,1.976 6.507,2.438 2.475,0.466 5.031,0.698 7.665,0.698 6.505,0 11.537,-1.082 15.103,-3.253 3.561,-2.166 6.192,-4.762 7.9,-7.785 1.702,-3.019 2.749,-6.072 3.137,-9.174 0.384,-3.097 0.58,-5.576 0.58,-7.434 V 172.93 c -1.396,1.243 -3.138,2.21 -5.23,2.908 z" />
<path
d="m 463.825,111.595 v 22.072 h -24.161 v 59.479 c 0,5.573 0.928,9.292 2.788,11.149 1.856,1.859 5.576,2.788 11.152,2.788 1.859,0 3.638,-0.076 5.343,-0.232 1.703,-0.152 3.33,-0.388 4.878,-0.696 v 25.557 c -2.788,0.465 -5.887,0.773 -9.293,0.931 -3.407,0.149 -6.737,0.23 -10,0.23 -5.111,0 -9.953,-0.35 -14.521,-1.048 -4.571,-0.695 -8.597,-2.047 -12.081,-4.063 -3.486,-2.011 -6.236,-4.88 -8.248,-8.597 -2.016,-3.714 -3.021,-8.595 -3.021,-14.639 v -70.859 h -19.98 v -22.072 h 19.98 V 75.583 h 33 v 36.012 z" />
<path
d="M 510.988,111.595 V 133.9 h 0.465 c 1.546,-3.72 3.636,-7.163 6.272,-10.341 2.634,-3.172 5.652,-5.885 9.06,-8.131 3.405,-2.242 7.047,-3.985 10.923,-5.228 3.868,-1.237 7.898,-1.859 12.081,-1.859 2.168,0 4.566,0.39 7.202,1.163 v 30.67 c -1.551,-0.312 -3.41,-0.584 -5.576,-0.814 -2.17,-0.233 -4.26,-0.35 -6.274,-0.35 -6.041,0 -11.152,1.01 -15.332,3.021 -4.182,2.014 -7.55,4.761 -10.107,8.247 -2.555,3.487 -4.379,7.55 -5.462,12.198 -1.083,4.645 -1.625,9.682 -1.625,15.102 v 54.133 H 479.624 V 111.595 Z" />
<path
d="M 570.93,93 V 65.824 h 33 v 27.183 z m 33,18.588 V 231.712 H 570.93 V 111.595 Z" />
<path
d="m 621.115,111.595 h 37.637 l 21.144,31.365 20.911,-31.365 h 36.476 l -39.496,56.226 44.377,63.892 h -37.64 l -25.093,-37.87 -25.094,37.87 h -36.938 l 43.213,-63.193 z" />
<path
d="M 782.443,331.097 V 9.711 h -23.13 v -7.71 h 32 v 336.807 h -32 v -7.711 z" />
</svg>

After

Width:  |  Height:  |  Size: 4.8 KiB