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 - Current focus
- Merge login page - Merge login page
- Just import nio?
- Refactoring - Refactoring
- Migrate more JS functions to their own files / Implement in Python instead - 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 - Bug when resizing window being tiled (i3), can't figure it out
- UI - UI
- Leave room
- Forget room warning popup
- Use HRowLayout and its totalSpacing wherever possible - Use HRowLayout and its totalSpacing wherever possible
- Spacer component - Spacer component
- One line label componant - One line label componant
@ -34,6 +37,8 @@
- Status message and presence - Status message and presence
- Client improvements - Client improvements
- HTTP/2
- `retry_after_ms` when rate-limited
- Direct chats category - Direct chats category
- On sync, check messages API, if a limited sync timeline was received - On sync, check messages API, if a limited sync timeline was received
- Markdown: don't turn #things into title (space), disable __ syntax - 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, - When inviting someone to direct chat, room is "Empty room" until accepted,
it should be the peer's display name instead. it should be the peer's display name instead.
- Keep an accounts order - Keep an accounts order
- See `Qt.callLater()` potential usages
- Banner name color instead of bold
- Missing nio support - Missing nio support
- Forget room
- Left room events - Left room events
- `org.matrix.room.preview_urls` event - `org.matrix.room.preview_urls` event
- `m.room.aliases` event - `m.room.aliases` event
- Avatars
- Support "Empty room (was ...)" after peer left - 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) roomJoined = pyqtSignal(str)
roomLeft = pyqtSignal([str, dict], [str]) roomLeft = pyqtSignal([str, dict], [str])
roomAboutToBeForgotten = pyqtSignal(str)
roomSyncPrevBatchTokenReceived = pyqtSignal(str, str) roomSyncPrevBatchTokenReceived = pyqtSignal(str, str)
roomPastPrevBatchTokenReceived = pyqtSignal(str, str) roomPastPrevBatchTokenReceived = pyqtSignal(str, str)
roomEventReceived = pyqtSignal(str, str, dict) roomEventReceived = pyqtSignal(str, str, dict)
@ -259,4 +261,5 @@ class Client(QObject):
@pyqtSlot(str) @pyqtSlot(str)
@futurize() @futurize()
def forgetRoom(self, room_id: str) -> None: 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): class ClientManager(QObject):
clientAdded = pyqtSignal(Client) clientAdded = pyqtSignal(Client)
clientDeleted = pyqtSignal(str) clientDeleted = pyqtSignal(str)
_clientsUpdate = pyqtSignal() clientCountChanged = pyqtSignal(int)
def __init__(self, backend: Backend) -> None: def __init__(self, backend: Backend) -> None:
@ -33,19 +33,25 @@ class ClientManager(QObject):
self.backend = backend self.backend = backend
self._clients: Dict[str, Client] = {} self._clients: Dict[str, Client] = {}
self.clientAdded.connect(self._clientsUpdate.emit) func = lambda: self.clientCountChanged.emit(len(self.clients))
self.clientDeleted.connect(self._clientsUpdate.emit) self.clientAdded.connect(func)
self.clientDeleted.connect(func)
def __repr__(self) -> str: def __repr__(self) -> str:
return f"{type(self).__name__}(clients={self.clients!r})" return f"{type(self).__name__}(clients={self.clients!r})"
@pyqtProperty("QVariantMap", notify=_clientsUpdate) @pyqtProperty("QVariantMap", notify=clientCountChanged)
def clients(self): def clients(self):
return self._clients return self._clients
@pyqtProperty(int, notify=clientCountChanged)
def clientCount(self):
return len(self.clients)
@pyqtSlot() @pyqtSlot()
def configLoad(self) -> None: def configLoad(self) -> None:
for user_id, info in self.configAccounts().items(): for user_id, info in self.configAccounts().items():

View File

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

View File

@ -268,3 +268,11 @@ class SignalManager(QObject):
self._events_in_transfer += 1 self._events_in_transfer += 1
self._move_room(client.userId, room_id) 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 { Loader {
anchors.fill: parent anchors.fill: parent
source: "UI.qml" source: Backend.clientManager.clientCount < 1 ?
"pages/LoginPage.qml" : "pages/MainUI.qml"
objectName: "UILoader" objectName: "UILoader"
} }
} }

View File

@ -3,9 +3,73 @@ import QtQuick.Controls 2.2
import QtQuick.Layouts 1.4 import QtQuick.Layouts 1.4
Button { Button {
property alias fontSize: buttonLabel.font.pixelSize
property color backgroundColor: "lightgray"
property alias overlayOpacity: buttonBackgroundOverlay.opacity
property string iconName: "" property string iconName: ""
property bool circle: false
id: button id: button
display: Button.TextBesideIcon 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 2.7
import QtQuick.Controls 2.0 import QtQuick.Controls 2.0
import "."
Label { Label {
property int bigSize: 24 font.family: HStyle.fontFamily.sans
property int normalSize: 16 font.pixelSize: HStyle.fontSize.normal
property int smallSize: 12
font.family: "Roboto"
font.pixelSize: normalSize
textFormat: Text.PlainText 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 Layout.preferredHeight: 32
color: "#BBB" color: "#BBB"
signal buttonClicked(string signalId)
property alias avatarName: bannerAvatar.name property alias avatarName: bannerAvatar.name
property alias avatarSource: bannerAvatar.imageSource property alias avatarSource: bannerAvatar.imageSource
property alias labelText: bannerLabel.text property alias labelText: bannerLabel.text
@ -77,8 +79,6 @@ Rectangle {
text: modelData.text text: modelData.text
iconName: modelData.iconName iconName: modelData.iconName
icon.color: modelData.iconColor
icon.width: 32
display: bannerButtons.displayMode display: bannerButtons.displayMode
onClicked: { onClicked: {
@ -87,14 +87,20 @@ Rectangle {
iconName = "hourglass" iconName = "hourglass"
alreadyClicked = true alreadyClicked = true
// modelData might become undefined after Backend call
var signalId = modelData.signalId
var iconName_ = modelData.iconName
var future = var future =
Backend.clientManager.clients[chatPage.userId]. Backend.clientManager.clients[chatPage.userId].
call(modelData.clientFunction, call(modelData.clientFunction,
modelData.clientArgs) modelData.clientArgs)
future.onGotResult.connect( future.onGotResult.connect(function() {
function() { iconName = modelData.iconName } iconName = iconName_
) })
if (signalId) { buttonClicked(signalId) }
} }
Layout.maximumWidth: bannerButtons.compact ? height : -1 Layout.maximumWidth: bannerButtons.compact ? height : -1

View File

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

View File

@ -27,7 +27,8 @@ RowLayout {
(displayName.value || dict.sender) + (displayName.value || dict.sender) +
(contentText.startsWith("'s ") ? "" : " ") + (contentText.startsWith("'s ") ? "" : " ") +
contentText + 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") + Qt.formatDateTime(dateTime, "hh:mm:ss") +
"</font></font>" "</font></font>"
textFormat: Text.RichText textFormat: Text.RichText

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -9,6 +9,8 @@ ColumnLayout {
readonly property var roomInfo: readonly property var roomInfo:
Backend.models.rooms.get(userId).getWhere("roomId", roomId) Backend.models.rooms.get(userId).getWhere("roomId", roomId)
property bool canLoadPastEvents: true
Component.onCompleted: console.log("replaced") 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 1.4 as Controls1
import QtQuick.Controls 2.2 import QtQuick.Controls 2.2
import QtQuick.Layouts 1.4 import QtQuick.Layouts 1.4
import "sidePane" as SidePane import "../sidePane" as SidePane
import "chat" as Chat import "../chat" as Chat
//https://doc.qt.io/qt-5/qml-qtquick-controls-splitview.html //https://doc.qt.io/qt-5/qml-qtquick-controls-splitview.html
Controls1.SplitView { Controls1.SplitView {
@ -17,13 +17,15 @@ Controls1.SplitView {
StackView { StackView {
function showRoom(userId, roomId) { function showRoom(userId, roomId) {
pageStack.replace( pageStack.replace(
"chat/Root.qml", { userId: userId, roomId: roomId } "../chat/Root.qml", { userId: userId, roomId: roomId }
) )
} }
id: pageStack id: pageStack
onCurrentItemChanged: currentItem.forceActiveFocus() onCurrentItemChanged: if (currentItem) {
currentItem.forceActiveFocus()
}
initialItem: Item { // TODO: (test, remove) initialItem: Item { // TODO: (test, remove)
Keys.onEnterPressed: pageStack.showRoom( 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() text: getText()
textFormat: Text.StyledText textFormat: Text.StyledText
font.pixelSize: smallSize font.pixelSize: Base.HStyle.fontSize.small
elide: Text.ElideRight elide: Text.ElideRight
maximumLineCount: 1 maximumLineCount: 1
Layout.maximumWidth: roomLabel.Layout.maximumWidth 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