Add login page and forget room system
33
README.md
|
@ -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
|
@ -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
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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():
|
||||||
|
|
|
@ -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()
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
22
harmonyqml/components/base/HStyle.qml
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
9
harmonyqml/components/base/HTextField.qml
Normal 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
|
||||||
|
}
|
1
harmonyqml/components/base/qmldir
Normal file
|
@ -0,0 +1 @@
|
||||||
|
singleton HStyle 1.0 HStyle.qml
|
|
@ -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
|
||||||
|
|
|
@ -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"
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,8 @@ RowLayout {
|
||||||
(displayName.value || dict.sender) +
|
(displayName.value || dict.sender) +
|
||||||
(contentText.startsWith("'s ") ? "" : " ") +
|
(contentText.startsWith("'s ") ? "" : " ") +
|
||||||
contentText +
|
contentText +
|
||||||
" <font size=" + smallSize + "px color='gray'>" +
|
" <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
|
||||||
|
|
|
@ -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],
|
||||||
}
|
}
|
||||||
|
|
|
@ -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],
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) +
|
||||||
" <font size=" + smallSize + "px color=gray>" +
|
" <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 ?
|
||||||
" <font size=" + smallSize + "px>⏳</font>" : "")
|
" <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
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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")
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
import QtQuick 2.7
|
|
||||||
import "../base" as Base
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
Base.HLabel {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
text: "Add account page"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
import QtQuick 2.7
|
|
||||||
import "../base" as Base
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
Base.HLabel {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
text: "Add room page"
|
|
||||||
}
|
|
||||||
}
|
|
122
harmonyqml/components/pages/LoginPage.qml
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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(
|
|
@ -1,9 +0,0 @@
|
||||||
import QtQuick 2.7
|
|
||||||
import "../base" as Base
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
Base.HLabel {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
text: "Settings page"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
||||||
|
|
|
@ -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 |
|
@ -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 |
1
harmonyqml/icons/email.svg
Normal 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 |
51
harmonyqml/icons/forget_room.svg
Normal 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 |
51
harmonyqml/icons/invite_accept.svg
Normal 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 |
51
harmonyqml/icons/invite_decline.svg
Normal 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 |
1
harmonyqml/icons/phone.svg
Normal 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 |
1
harmonyqml/icons/placeholder.svg
Normal 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 |
|
@ -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 |
1
harmonyqml/icons/username.svg
Normal 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 |
BIN
harmonyqml/images/login_background.jpg
Normal file
After Width: | Height: | Size: 1.8 MiB |
26
harmonyqml/images/matrix_logo.svg
Normal 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 |