summary refs log tree commit diff
path: root/resources
diff options
context:
space:
mode:
authorDeepBlueV7.X <nicolas.werner@hotmail.de>2022-01-30 19:18:32 +0000
committerGitHub <noreply@github.com>2022-01-30 19:18:32 +0000
commitb706e272e55bb98bc2c09813339372d7e34c44a6 (patch)
tree06d017ce059044b25862360d8702a9ef727dca17 /resources
parentMerge pull request #909 from tastytea/rename-manpage (diff)
parentFix list items being hoverable through between settings and new room buttons (diff)
downloadnheko-b706e272e55bb98bc2c09813339372d7e34c44a6.tar.xz
Merge pull request #893 from Nheko-Reborn/qml-root
Qml root
Diffstat (limited to 'resources')
-rw-r--r--resources/langs/nheko_de.ts2
-rw-r--r--resources/qml/ChatPage.qml1
-rw-r--r--resources/qml/MatrixTextField.qml143
-rw-r--r--resources/qml/PrivacyScreen.qml5
-rw-r--r--resources/qml/QuickSwitcher.qml4
-rw-r--r--resources/qml/RoomList.qml27
-rw-r--r--resources/qml/Root.qml58
-rw-r--r--resources/qml/TopBar.qml400
-rw-r--r--resources/qml/components/FlatButton.qml4
-rw-r--r--resources/qml/device-verification/DeviceVerification.qml1
-rw-r--r--resources/qml/dialogs/ImagePackEditorDialog.qml52
-rw-r--r--resources/qml/dialogs/ImagePackSettingsDialog.qml1
-rw-r--r--resources/qml/dialogs/InputDialog.qml1
-rw-r--r--resources/qml/dialogs/InviteDialog.qml1
-rw-r--r--resources/qml/dialogs/JoinRoomDialog.qml1
-rw-r--r--resources/qml/dialogs/PhoneNumberInputDialog.qml1
-rw-r--r--resources/qml/dialogs/RawMessageDialog.qml1
-rw-r--r--resources/qml/dialogs/ReadReceipts.qml1
-rw-r--r--resources/qml/dialogs/RoomDirectory.qml3
-rw-r--r--resources/qml/dialogs/RoomMembers.qml1
-rw-r--r--resources/qml/dialogs/RoomSettings.qml1
-rw-r--r--resources/qml/dialogs/UserProfile.qml4
-rw-r--r--resources/qml/pages/LoginPage.qml182
-rw-r--r--resources/qml/pages/RegisterPage.qml215
-rw-r--r--resources/qml/pages/WelcomePage.qml73
-rw-r--r--resources/qml/ui/Snackbar.qml98
-rw-r--r--resources/res.qrc4
27 files changed, 1004 insertions, 281 deletions
diff --git a/resources/langs/nheko_de.ts b/resources/langs/nheko_de.ts

index 29a04355..c499874b 100644 --- a/resources/langs/nheko_de.ts +++ b/resources/langs/nheko_de.ts
@@ -319,7 +319,7 @@ <message> <location line="+66"/> <source>Failed to kick %1 from %2: %3</source> - <translation>Kontte %1 nicht aus %2 entfernen: %3</translation> + <translation>Konnte %1 nicht aus %2 entfernen: %3</translation> </message> </context> <context> diff --git a/resources/qml/ChatPage.qml b/resources/qml/ChatPage.qml
index 33db1b1a..e3aa3e48 100644 --- a/resources/qml/ChatPage.qml +++ b/resources/qml/ChatPage.qml
@@ -97,6 +97,7 @@ Rectangle { implicitHeight: chatPage.height collapsed: parent.collapsed + anchors.fill: parent } Binding { diff --git a/resources/qml/MatrixTextField.qml b/resources/qml/MatrixTextField.qml
index af077124..05f2c82f 100644 --- a/resources/qml/MatrixTextField.qml +++ b/resources/qml/MatrixTextField.qml
@@ -8,29 +8,139 @@ import QtQuick.Controls 2.12 import QtQuick.Layouts 1.12 import im.nheko 1.0 -TextField { - id: input - property alias backgroundColor: backgroundRect.color +ColumnLayout { + id: c + property color backgroundColor: Nheko.colors.base + property alias color: labelC.color + property alias textPadding: input.padding + property alias text: input.text + property alias label: labelC.text + property alias placeholderText: input.placeholderText + property alias font: input.font + property alias echoMode: input.echoMode + property alias selectByMouse: input.selectByMouse - palette: Nheko.colors - color: Nheko.colors.text + Timer { + id: timer + interval: 350 + onTriggered: editingFinished() + } + + onTextChanged: timer.restart() + + signal textEdited + signal accepted + signal editingFinished + + function forceActiveFocus() { + input.forceActiveFocus(); + } + + ToolTip.delay: Nheko.tooltipDelay + ToolTip.visible: hover.hovered + + spacing: 0 + + Item { + Layout.fillWidth: true + Layout.preferredHeight: labelC.contentHeight + Layout.margins: input.padding + Layout.bottomMargin: Nheko.paddingSmall + visible: labelC.text + + z: 1 + + Label { + id: labelC + + y: contentHeight + input.padding + Nheko.paddingSmall + enabled: false + + palette: Nheko.colors + color: Nheko.colors.text + font.pixelSize: input.font.pixelSize + font.weight: Font.DemiBold + font.letterSpacing: input.font.pixelSize * 0.02 + width: parent.width + + state: labelC.text && (input.activeFocus == true || input.text) ? "focused" : "" + + states: State { + name: "focused" + + PropertyChanges { + target: labelC + y: 0 + } + + PropertyChanges { + target: input + opacity: 1 + } + + } + + transitions: Transition { + from: "" + to: "focused" + reversible: true + + NumberAnimation { + target: labelC + properties: "y" + duration: 210 + easing.type: Easing.InCubic + alwaysRunToEnd: true + } + + NumberAnimation { + target: input + properties: "opacity" + duration: 210 + easing.type: Easing.InCubic + alwaysRunToEnd: true + } + + } + } + } + + TextField { + id: input + Layout.fillWidth: true + + palette: Nheko.colors + color: labelC.color + opacity: labelC.text ? 0 : 1 + + onTextEdited: c.textEdited() + onAccepted: c.accepted() + onEditingFinished: c.editingFinished() + + + background: Rectangle { + id: backgroundRect + + color: labelC.text ? "transparent" : backgroundColor + } + + } Rectangle { id: blueBar - anchors.top: parent.bottom - anchors.horizontalCenter: parent.horizontalCenter + Layout.fillWidth: true + color: Nheko.colors.highlight height: 1 - width: parent.width Rectangle { id: blackBar - anchors.verticalCenter: blueBar.verticalCenter + anchors.top: parent.top anchors.horizontalCenter: parent.horizontalCenter - height: parent.height + 1 + height: parent.height*2 width: 0 color: Nheko.colors.text @@ -50,11 +160,12 @@ TextField { to: "focused" reversible: true + NumberAnimation { target: blackBar properties: "width" - duration: 500 - easing.type: Easing.InOutQuad + duration: 310 + easing.type: Easing.InCubic alwaysRunToEnd: true } @@ -64,10 +175,8 @@ TextField { } - background: Rectangle { - id: backgroundRect - - color: Nheko.colors.base + HoverHandler { + id: hover + enabled: c.ToolTip.text } - } diff --git a/resources/qml/PrivacyScreen.qml b/resources/qml/PrivacyScreen.qml
index e6286bc6..fb3818df 100644 --- a/resources/qml/PrivacyScreen.qml +++ b/resources/qml/PrivacyScreen.qml
@@ -5,6 +5,7 @@ import QtGraphicalEffects 1.0 import QtQuick 2.12 +import QtQuick.Window 2.2 import im.nheko 1.0 Item { @@ -15,7 +16,7 @@ Item { Connections { function onFocusChanged() { - if (TimelineManager.isWindowFocused) { + if (MainWindow.active) { screenSaverTimer.stop(); screenSaver.state = "Invisible"; } else { @@ -32,7 +33,7 @@ Item { id: screenSaverTimer interval: screenTimeout * 1000 - running: true + running: !MainWindow.active onTriggered: { screenSaver.state = "Visible"; } diff --git a/resources/qml/QuickSwitcher.qml b/resources/qml/QuickSwitcher.qml
index 174951a0..8747c47d 100644 --- a/resources/qml/QuickSwitcher.qml +++ b/resources/qml/QuickSwitcher.qml
@@ -11,7 +11,6 @@ Popup { id: quickSwitcher property int textHeight: Math.round(Qt.application.font.pixelSize * 2.4) - property int textMargin: Math.round(textHeight / 8) background: null width: Math.round(parent.width / 2) @@ -34,7 +33,6 @@ Popup { anchors.fill: parent font.pixelSize: Math.ceil(quickSwitcher.textHeight * 0.6) - padding: textMargin color: Nheko.colors.text onTextEdited: { completerPopup.completer.searchString = text; @@ -60,7 +58,7 @@ Popup { id: completerPopup x: roomTextInput.x - y: roomTextInput.y + quickSwitcher.textHeight + quickSwitcher.textMargin + y: roomTextInput.y + quickSwitcher.textHeight visible: roomTextInput.length > 0 width: parent.width completerName: "room" diff --git a/resources/qml/RoomList.qml b/resources/qml/RoomList.qml
index 6e7b683f..da205950 100644 --- a/resources/qml/RoomList.qml +++ b/resources/qml/RoomList.qml
@@ -385,7 +385,7 @@ Page { header: ColumnLayout { spacing: 0 - Rectangle { + Pane { id: userInfoPanel function openUserProfile() { @@ -396,12 +396,15 @@ Page { userProfile.show(); } - color: Nheko.colors.window + Layout.fillWidth: true Layout.alignment: Qt.AlignBottom - Layout.preferredHeight: userInfoGrid.implicitHeight + 2 * Nheko.paddingMedium + //Layout.preferredHeight: userInfoGrid.implicitHeight + 2 * Nheko.paddingMedium + padding: Nheko.paddingMedium Layout.minimumHeight: 40 + background: Rectangle {color: Nheko.colors.window} + InputDialog { id: statusDialog @@ -442,14 +445,12 @@ Page { gesturePolicy: TapHandler.ReleaseWithinBounds } - RowLayout { + contentItem: RowLayout { id: userInfoGrid property var profile: Nheko.currentUser spacing: Nheko.paddingMedium - anchors.fill: parent - anchors.margins: Nheko.paddingMedium Avatar { id: avatar @@ -614,19 +615,17 @@ Page { Layout.fillWidth: true } - Rectangle { - color: Nheko.colors.window + Pane { Layout.fillWidth: true Layout.alignment: Qt.AlignBottom - Layout.preferredHeight: buttonRow.implicitHeight Layout.minimumHeight: 40 - RowLayout { - id: buttonRow + horizontalPadding: Nheko.paddingMedium + verticalPadding: 0 - anchors.left: parent.left - anchors.right: parent.right - anchors.margins: Nheko.paddingMedium + background: Rectangle {color: Nheko.colors.window} + contentItem: RowLayout { + id: buttonRow ImageButton { Layout.fillWidth: true diff --git a/resources/qml/Root.qml b/resources/qml/Root.qml
index e4b164e4..88d3e7c6 100644 --- a/resources/qml/Root.qml +++ b/resources/qml/Root.qml
@@ -9,6 +9,7 @@ import "./dialogs" import "./emoji" import "./pages" import "./voip" +import "./ui" import Qt.labs.platform 1.1 as Platform import QtQuick 2.15 import QtQuick.Controls 2.15 @@ -17,10 +18,12 @@ import QtQuick.Window 2.15 import im.nheko 1.0 import im.nheko.EmojiModel 1.0 -Page { +Pane { id: timelineRoot palette: Nheko.colors + background: null + padding: 0 FontMetrics { id: fontMetrics @@ -154,10 +157,14 @@ Page { } Shortcut { + sequence: StandardKey.Quit + onActivated: Qt.quit() + } + + Shortcut { sequence: "Ctrl+K" onActivated: { var quickSwitch = quickSwitcherComponent.createObject(timelineRoot); - TimelineManager.focusTimeline(); quickSwitch.open(); } } @@ -165,7 +172,6 @@ Page { Shortcut { // Add alternative shortcut, because sometimes Alt+A is stolen by the TextEdit sequences: ["Alt+A", "Ctrl+Shift+A"] - context: Qt.ApplicationShortcut onActivated: Rooms.nextRoomWithActivity() } @@ -366,9 +372,51 @@ Page { id: mainWindow anchors.fill: parent - initialItem: ChatPage { - //anchors.fill: parent + initialItem: welcomePage + } + + Component { + id: welcomePage + + WelcomePage { + } + } + + Component { + id: chatPage + + ChatPage { + } + } + + Component { + id: loginPage + + LoginPage { + } + } + + Component { + id: registerPage + + RegisterPage { + } + } + + Snackbar { id: snackbar } + + Connections { + function onSwitchToChatPage() { + mainWindow.replace(null, chatPage); + } + function onSwitchToLoginPage(error) { + mainWindow.replace(welcomePage, {}, loginPage, {"error": error}, StackView.PopTransition); + } + function onShowNotification(msg) { + snackbar.showNotification(msg); + console.log("New snack: " + msg); } + target: MainWindow } } diff --git a/resources/qml/TopBar.qml b/resources/qml/TopBar.qml
index 1c0115e2..c9a8d0d2 100644 --- a/resources/qml/TopBar.qml +++ b/resources/qml/TopBar.qml
@@ -12,7 +12,7 @@ import im.nheko 1.0 import "./delegates" -Rectangle { +Pane { id: topBar property bool showBackButton: false @@ -28,7 +28,11 @@ Rectangle { Layout.fillWidth: true implicitHeight: topLayout.height + Nheko.paddingMedium * 2 z: 3 - color: Nheko.colors.window + + padding: 0 + background: Rectangle { + color: Nheko.colors.window + } TapHandler { onSingleTapped: { @@ -65,248 +69,250 @@ Rectangle { grabPermissions: PointerHandler.TakeOverForbidden | PointerHandler.CanTakeOverFromAnything } - GridLayout { - id: topLayout + contentItem: Item { + GridLayout { + id: topLayout - anchors.left: parent.left - anchors.right: parent.right - anchors.margins: Nheko.paddingMedium - anchors.verticalCenter: parent.verticalCenter - columnSpacing: Nheko.paddingSmall - rowSpacing: Nheko.paddingSmall + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: Nheko.paddingMedium + anchors.verticalCenter: parent.verticalCenter + columnSpacing: Nheko.paddingSmall + rowSpacing: Nheko.paddingSmall - ImageButton { - id: backToRoomsButton + ImageButton { + id: backToRoomsButton - Layout.column: 0 - Layout.row: 0 - Layout.rowSpan: 2 - Layout.alignment: Qt.AlignVCenter - Layout.preferredHeight: Nheko.avatarSize - Nheko.paddingMedium - Layout.preferredWidth: Nheko.avatarSize - Nheko.paddingMedium - visible: showBackButton - image: ":/icons/icons/ui/angle-arrow-left.svg" - ToolTip.visible: hovered - ToolTip.text: qsTr("Back to room list") - onClicked: Rooms.resetCurrentRoom() - } + Layout.column: 0 + Layout.row: 0 + Layout.rowSpan: 2 + Layout.alignment: Qt.AlignVCenter + Layout.preferredHeight: Nheko.avatarSize - Nheko.paddingMedium + Layout.preferredWidth: Nheko.avatarSize - Nheko.paddingMedium + visible: showBackButton + image: ":/icons/icons/ui/angle-arrow-left.svg" + ToolTip.visible: hovered + ToolTip.text: qsTr("Back to room list") + onClicked: Rooms.resetCurrentRoom() + } - Avatar { - Layout.column: 1 - Layout.row: 0 - Layout.rowSpan: 2 - Layout.alignment: Qt.AlignVCenter - width: Nheko.avatarSize - height: Nheko.avatarSize - url: avatarUrl.replace("mxc://", "image://MxcImage/") - roomid: roomId - userid: isDirect ? directChatOtherUserId : "" - displayName: roomName - enabled: false - } + Avatar { + Layout.column: 1 + Layout.row: 0 + Layout.rowSpan: 2 + Layout.alignment: Qt.AlignVCenter + width: Nheko.avatarSize + height: Nheko.avatarSize + url: avatarUrl.replace("mxc://", "image://MxcImage/") + roomid: roomId + userid: isDirect ? directChatOtherUserId : "" + displayName: roomName + enabled: false + } - Label { - Layout.fillWidth: true - Layout.column: 2 - Layout.row: 0 - color: Nheko.colors.text - font.pointSize: fontMetrics.font.pointSize * 1.1 - text: roomName - maximumLineCount: 1 - elide: Text.ElideRight - textFormat: Text.RichText - } + Label { + Layout.fillWidth: true + Layout.column: 2 + Layout.row: 0 + color: Nheko.colors.text + font.pointSize: fontMetrics.font.pointSize * 1.1 + text: roomName + maximumLineCount: 1 + elide: Text.ElideRight + textFormat: Text.RichText + } - MatrixText { - id: roomTopicC - Layout.fillWidth: true - Layout.column: 2 - Layout.row: 1 - Layout.maximumHeight: fontMetrics.lineSpacing * 2 // show 2 lines - selectByMouse: false - enabled: false - clip: true - text: roomTopic - } + MatrixText { + id: roomTopicC + Layout.fillWidth: true + Layout.column: 2 + Layout.row: 1 + Layout.maximumHeight: fontMetrics.lineSpacing * 2 // show 2 lines + selectByMouse: false + enabled: false + clip: true + text: roomTopic + } - EncryptionIndicator { - Layout.column: 3 - Layout.row: 0 - Layout.rowSpan: 2 - Layout.preferredHeight: Nheko.avatarSize - Nheko.paddingMedium - Layout.preferredWidth: Nheko.avatarSize - Nheko.paddingMedium - sourceSize.height: Layout.preferredHeight * Screen.devicePixelRatio - sourceSize.width: Layout.preferredWidth * Screen.devicePixelRatio - visible: isEncrypted - encrypted: isEncrypted - trust: trustlevel - ToolTip.text: { - if (!encrypted) - return qsTr("This room is not encrypted!"); + EncryptionIndicator { + Layout.column: 3 + Layout.row: 0 + Layout.rowSpan: 2 + Layout.preferredHeight: Nheko.avatarSize - Nheko.paddingMedium + Layout.preferredWidth: Nheko.avatarSize - Nheko.paddingMedium + sourceSize.height: Layout.preferredHeight * Screen.devicePixelRatio + sourceSize.width: Layout.preferredWidth * Screen.devicePixelRatio + visible: isEncrypted + encrypted: isEncrypted + trust: trustlevel + ToolTip.text: { + if (!encrypted) + return qsTr("This room is not encrypted!"); - switch (trust) { - case Crypto.Verified: - return qsTr("This room contains only verified devices."); - case Crypto.TOFU: - return qsTr("This room contains verified devices and devices which have never changed their master key."); - default: - return qsTr("This room contains unverified devices!"); + switch (trust) { + case Crypto.Verified: + return qsTr("This room contains only verified devices."); + case Crypto.TOFU: + return qsTr("This room contains verified devices and devices which have never changed their master key."); + default: + return qsTr("This room contains unverified devices!"); + } } } - } - ImageButton { - id: pinButton + ImageButton { + id: pinButton - property bool pinsShown: !Settings.hiddenPins.includes(roomId) + property bool pinsShown: !Settings.hiddenPins.includes(roomId) - visible: !!room && room.pinnedMessages.length > 0 - Layout.column: 4 - Layout.row: 0 - Layout.rowSpan: 2 - Layout.alignment: Qt.AlignVCenter - Layout.preferredHeight: Nheko.avatarSize - Nheko.paddingMedium - Layout.preferredWidth: Nheko.avatarSize - Nheko.paddingMedium - image: pinsShown ? ":/icons/icons/ui/pin.svg" : ":/icons/icons/ui/pin-off.svg" - ToolTip.visible: hovered - ToolTip.text: qsTr("Show or hide pinned messages") - onClicked: { - var ps = Settings.hiddenPins; - if (pinsShown) { - ps.push(roomId); - } else { - const index = ps.indexOf(roomId); - if (index > -1) { - ps.splice(index, 1); + visible: !!room && room.pinnedMessages.length > 0 + Layout.column: 4 + Layout.row: 0 + Layout.rowSpan: 2 + Layout.alignment: Qt.AlignVCenter + Layout.preferredHeight: Nheko.avatarSize - Nheko.paddingMedium + Layout.preferredWidth: Nheko.avatarSize - Nheko.paddingMedium + image: pinsShown ? ":/icons/icons/ui/pin.svg" : ":/icons/icons/ui/pin-off.svg" + ToolTip.visible: hovered + ToolTip.text: qsTr("Show or hide pinned messages") + onClicked: { + var ps = Settings.hiddenPins; + if (pinsShown) { + ps.push(roomId); + } else { + const index = ps.indexOf(roomId); + if (index > -1) { + ps.splice(index, 1); + } } + Settings.hiddenPins = ps; } - Settings.hiddenPins = ps; + } - } + ImageButton { + id: roomOptionsButton - ImageButton { - id: roomOptionsButton + visible: !!room + Layout.column: 5 + Layout.row: 0 + Layout.rowSpan: 2 + Layout.alignment: Qt.AlignVCenter + Layout.preferredHeight: Nheko.avatarSize - Nheko.paddingMedium + Layout.preferredWidth: Nheko.avatarSize - Nheko.paddingMedium + image: ":/icons/icons/ui/options.svg" + ToolTip.visible: hovered + ToolTip.text: qsTr("Room options") + onClicked: roomOptionsMenu.open(roomOptionsButton) - visible: !!room - Layout.column: 5 - Layout.row: 0 - Layout.rowSpan: 2 - Layout.alignment: Qt.AlignVCenter - Layout.preferredHeight: Nheko.avatarSize - Nheko.paddingMedium - Layout.preferredWidth: Nheko.avatarSize - Nheko.paddingMedium - image: ":/icons/icons/ui/options.svg" - ToolTip.visible: hovered - ToolTip.text: qsTr("Room options") - onClicked: roomOptionsMenu.open(roomOptionsButton) + Platform.Menu { + id: roomOptionsMenu - Platform.Menu { - id: roomOptionsMenu + Platform.MenuItem { + visible: room ? room.permissions.canInvite() : false + text: qsTr("Invite users") + onTriggered: TimelineManager.openInviteUsers(roomId) + } - Platform.MenuItem { - visible: room ? room.permissions.canInvite() : false - text: qsTr("Invite users") - onTriggered: TimelineManager.openInviteUsers(roomId) - } + Platform.MenuItem { + text: qsTr("Members") + onTriggered: TimelineManager.openRoomMembers(room) + } - Platform.MenuItem { - text: qsTr("Members") - onTriggered: TimelineManager.openRoomMembers(room) - } + Platform.MenuItem { + text: qsTr("Leave room") + onTriggered: TimelineManager.openLeaveRoomDialog(roomId) + } - Platform.MenuItem { - text: qsTr("Leave room") - onTriggered: TimelineManager.openLeaveRoomDialog(roomId) - } + Platform.MenuItem { + text: qsTr("Settings") + onTriggered: TimelineManager.openRoomSettings(roomId) + } - Platform.MenuItem { - text: qsTr("Settings") - onTriggered: TimelineManager.openRoomSettings(roomId) } } - } - - ScrollView { - id: pinnedMessages + ScrollView { + id: pinnedMessages - Layout.row: 2 - Layout.column: 2 - Layout.columnSpan: 3 + Layout.row: 2 + Layout.column: 2 + Layout.columnSpan: 3 - Layout.fillWidth: true - Layout.preferredHeight: Math.min(contentHeight, Nheko.avatarSize * 4) + Layout.fillWidth: true + Layout.preferredHeight: Math.min(contentHeight, Nheko.avatarSize * 4) - visible: !!room && room.pinnedMessages.length > 0 && !Settings.hiddenPins.includes(roomId) - clip: true + visible: !!room && room.pinnedMessages.length > 0 && !Settings.hiddenPins.includes(roomId) + clip: true - palette: Nheko.colors - ScrollBar.horizontal.visible: false + palette: Nheko.colors + ScrollBar.horizontal.visible: false - ListView { + ListView { - spacing: Nheko.paddingSmall - model: room ? room.pinnedMessages : undefined - delegate: RowLayout { - required property string modelData + spacing: Nheko.paddingSmall + model: room ? room.pinnedMessages : undefined + delegate: RowLayout { + required property string modelData - width: ListView.view.width - height: implicitHeight + width: ListView.view.width + height: implicitHeight - Reply { - property var e: room ? room.getDump(modelData, "") : {} - Layout.fillWidth: true - Layout.preferredHeight: height + Reply { + property var e: room ? room.getDump(modelData, "") : {} + Layout.fillWidth: true + Layout.preferredHeight: height - userColor: TimelineManager.userColor(e.userId, Nheko.colors.window) - blurhash: e.blurhash ?? "" - body: e.body ?? "" - formattedBody: e.formattedBody ?? "" - eventId: e.eventId ?? "" - filename: e.filename ?? "" - filesize: e.filesize ?? "" - proportionalHeight: e.proportionalHeight ?? 1 - type: e.type ?? MtxEvent.UnknownMessage - typeString: e.typeString ?? "" - url: e.url ?? "" - originalWidth: e.originalWidth ?? 0 - isOnlyEmoji: e.isOnlyEmoji ?? false - userId: e.userId ?? "" - userName: e.userName ?? "" - encryptionError: e.encryptionError ?? "" - } + userColor: TimelineManager.userColor(e.userId, Nheko.colors.window) + blurhash: e.blurhash ?? "" + body: e.body ?? "" + formattedBody: e.formattedBody ?? "" + eventId: e.eventId ?? "" + filename: e.filename ?? "" + filesize: e.filesize ?? "" + proportionalHeight: e.proportionalHeight ?? 1 + type: e.type ?? MtxEvent.UnknownMessage + typeString: e.typeString ?? "" + url: e.url ?? "" + originalWidth: e.originalWidth ?? 0 + isOnlyEmoji: e.isOnlyEmoji ?? false + userId: e.userId ?? "" + userName: e.userName ?? "" + encryptionError: e.encryptionError ?? "" + } - ImageButton { - id: deletePinButton + ImageButton { + id: deletePinButton - Layout.preferredHeight: 16 - Layout.preferredWidth: 16 - Layout.alignment: Qt.AlignTop | Qt.AlignLeft - visible: room.permissions.canChange(MtxEvent.PinnedEvents) + Layout.preferredHeight: 16 + Layout.preferredWidth: 16 + Layout.alignment: Qt.AlignTop | Qt.AlignLeft + visible: room.permissions.canChange(MtxEvent.PinnedEvents) - hoverEnabled: true - image: ":/icons/icons/ui/dismiss.svg" - ToolTip.visible: hovered - ToolTip.text: qsTr("Unpin") + hoverEnabled: true + image: ":/icons/icons/ui/dismiss.svg" + ToolTip.visible: hovered + ToolTip.text: qsTr("Unpin") - onClicked: room.unpin(modelData) + onClicked: room.unpin(modelData) + } } - } - ScrollHelper { - flickable: parent - anchors.fill: parent - enabled: !Settings.mobileMode + ScrollHelper { + flickable: parent + anchors.fill: parent + enabled: !Settings.mobileMode + } } } } - } - CursorShape { - anchors.fill: parent - anchors.bottomMargin: pinnedMessages.visible ? pinnedMessages.height : 0 - cursorShape: Qt.PointingHandCursor + CursorShape { + anchors.fill: parent + anchors.bottomMargin: pinnedMessages.visible ? pinnedMessages.height : 0 + cursorShape: Qt.PointingHandCursor + } } } diff --git a/resources/qml/components/FlatButton.qml b/resources/qml/components/FlatButton.qml
index 8ca3f104..72184d28 100644 --- a/resources/qml/components/FlatButton.qml +++ b/resources/qml/components/FlatButton.qml
@@ -12,7 +12,7 @@ import im.nheko 1.0 Button { id: control - implicitHeight: Math.ceil(control.contentItem.implicitHeight * 1.5) + implicitHeight: Math.ceil(control.contentItem.implicitHeight * 1.70) implicitWidth: Math.ceil(control.contentItem.implicitWidth + control.contentItem.implicitHeight) hoverEnabled: true @@ -42,7 +42,7 @@ Button { background: Rectangle { //height: control.contentItem.implicitHeight * 2 //width: control.contentItem.implicitWidth * 2 - radius: height / 6 + radius: height / 8 color: Qt.lighter(Nheko.colors.dark, control.down ? 1.4 : (control.hovered ? 1.2 : 1)) } diff --git a/resources/qml/device-verification/DeviceVerification.qml b/resources/qml/device-verification/DeviceVerification.qml
index c00a0bdb..90dc9ac4 100644 --- a/resources/qml/device-verification/DeviceVerification.qml +++ b/resources/qml/device-verification/DeviceVerification.qml
@@ -21,7 +21,6 @@ ApplicationWindow { minimumHeight: stack.implicitHeight width: stack.implicitWidth flags: Qt.Dialog | Qt.WindowCloseButtonHint | Qt.WindowTitleHint - Component.onCompleted: Nheko.reparent(dialog) StackView { id: stack diff --git a/resources/qml/dialogs/ImagePackEditorDialog.qml b/resources/qml/dialogs/ImagePackEditorDialog.qml
index 3ba04d94..eb420fce 100644 --- a/resources/qml/dialogs/ImagePackEditorDialog.qml +++ b/resources/qml/dialogs/ImagePackEditorDialog.qml
@@ -12,8 +12,6 @@ import QtQuick.Layouts 1.12 import im.nheko 1.0 ApplicationWindow { - //Component.onCompleted: Nheko.reparent(win) - id: win property int avatarSize: Math.ceil(fontMetrics.lineSpacing * 2.3) @@ -175,39 +173,37 @@ ApplicationWindow { } } - MatrixText { - visible: imagePack.roomid - text: qsTr("State key") - } - MatrixTextField { + id: statekeyField + visible: imagePack.roomid Layout.fillWidth: true + Layout.columnSpan: 2 + label: qsTr("State key") text: imagePack.statekey onTextEdited: imagePack.statekey = text } - MatrixText { - text: qsTr("Packname") - } - MatrixTextField { Layout.fillWidth: true + Layout.columnSpan: 2 + label: qsTr("Packname") text: imagePack.packname onTextEdited: imagePack.packname = text } - MatrixText { - text: qsTr("Attribution") - } - MatrixTextField { Layout.fillWidth: true + Layout.columnSpan: 2 + label: qsTr("Attribution") text: imagePack.attribution onTextEdited: imagePack.attribution = text } MatrixText { + Layout.margins: statekeyField.textPadding + font.weight: Font.DemiBold + font.letterSpacing: font.pixelSize * 0.02 text: qsTr("Use as Emoji") } @@ -218,6 +214,9 @@ ApplicationWindow { } MatrixText { + Layout.margins: statekeyField.textPadding + font.weight: Font.DemiBold + font.letterSpacing: font.pixelSize * 0.02 text: qsTr("Use as Sticker") } @@ -253,27 +252,28 @@ ApplicationWindow { Layout.alignment: Qt.AlignHCenter } - MatrixText { - text: qsTr("Shortcode") - } - MatrixTextField { Layout.fillWidth: true + Layout.columnSpan: 2 + label: qsTr("Shortcode") text: imagePack.data(imagePack.index(currentImageIndex, 0), SingleImagePackModel.ShortCode) onTextEdited: imagePack.setData(imagePack.index(currentImageIndex, 0), text, SingleImagePackModel.ShortCode) } - MatrixText { - text: qsTr("Body") - } - MatrixTextField { + id: bodyField + Layout.fillWidth: true + Layout.columnSpan: 2 + label: qsTr("Body") text: imagePack.data(imagePack.index(currentImageIndex, 0), SingleImagePackModel.Body) onTextEdited: imagePack.setData(imagePack.index(currentImageIndex, 0), text, SingleImagePackModel.Body) } MatrixText { + Layout.margins: bodyField.textPadding + font.weight: Font.DemiBold + font.letterSpacing: font.pixelSize * 0.02 text: qsTr("Use as Emoji") } @@ -284,6 +284,9 @@ ApplicationWindow { } MatrixText { + Layout.margins: bodyField.textPadding + font.weight: Font.DemiBold + font.letterSpacing: font.pixelSize * 0.02 text: qsTr("Use as Sticker") } @@ -294,6 +297,9 @@ ApplicationWindow { } MatrixText { + Layout.margins: bodyField.textPadding + font.weight: Font.DemiBold + font.letterSpacing: font.pixelSize * 0.02 text: qsTr("Remove from pack") } diff --git a/resources/qml/dialogs/ImagePackSettingsDialog.qml b/resources/qml/dialogs/ImagePackSettingsDialog.qml
index fa079855..18c32c41 100644 --- a/resources/qml/dialogs/ImagePackSettingsDialog.qml +++ b/resources/qml/dialogs/ImagePackSettingsDialog.qml
@@ -28,7 +28,6 @@ ApplicationWindow { color: Nheko.colors.base modality: Qt.NonModal flags: Qt.Dialog | Qt.WindowCloseButtonHint | Qt.WindowTitleHint - Component.onCompleted: Nheko.reparent(win) Component { id: packEditor diff --git a/resources/qml/dialogs/InputDialog.qml b/resources/qml/dialogs/InputDialog.qml
index 63ca3181..cf1474dc 100644 --- a/resources/qml/dialogs/InputDialog.qml +++ b/resources/qml/dialogs/InputDialog.qml
@@ -18,7 +18,6 @@ ApplicationWindow { modality: Qt.NonModal flags: Qt.Dialog - Component.onCompleted: Nheko.reparent(inputDialog) width: 350 height: fontMetrics.lineSpacing * 7 diff --git a/resources/qml/dialogs/InviteDialog.qml b/resources/qml/dialogs/InviteDialog.qml
index 917bc856..e7dd4e3a 100644 --- a/resources/qml/dialogs/InviteDialog.qml +++ b/resources/qml/dialogs/InviteDialog.qml
@@ -37,7 +37,6 @@ ApplicationWindow { palette: Nheko.colors color: Nheko.colors.window flags: Qt.Dialog | Qt.WindowCloseButtonHint | Qt.WindowTitleHint - Component.onCompleted: Nheko.reparent(inviteDialogRoot) Shortcut { sequence: "Ctrl+Enter" diff --git a/resources/qml/dialogs/JoinRoomDialog.qml b/resources/qml/dialogs/JoinRoomDialog.qml
index 9ce6bcf1..e49f538d 100644 --- a/resources/qml/dialogs/JoinRoomDialog.qml +++ b/resources/qml/dialogs/JoinRoomDialog.qml
@@ -17,7 +17,6 @@ ApplicationWindow { flags: Qt.Dialog | Qt.WindowCloseButtonHint | Qt.WindowTitleHint palette: Nheko.colors color: Nheko.colors.window - Component.onCompleted: Nheko.reparent(joinRoomRoot) width: 350 height: fontMetrics.lineSpacing * 7 diff --git a/resources/qml/dialogs/PhoneNumberInputDialog.qml b/resources/qml/dialogs/PhoneNumberInputDialog.qml
index 399b11d5..9c36c98f 100644 --- a/resources/qml/dialogs/PhoneNumberInputDialog.qml +++ b/resources/qml/dialogs/PhoneNumberInputDialog.qml
@@ -19,7 +19,6 @@ ApplicationWindow { modality: Qt.NonModal flags: Qt.Dialog - Component.onCompleted: Nheko.reparent(inputDialog) width: 350 height: fontMetrics.lineSpacing * 7 diff --git a/resources/qml/dialogs/RawMessageDialog.qml b/resources/qml/dialogs/RawMessageDialog.qml
index 34104394..774b078b 100644 --- a/resources/qml/dialogs/RawMessageDialog.qml +++ b/resources/qml/dialogs/RawMessageDialog.qml
@@ -17,7 +17,6 @@ ApplicationWindow { palette: Nheko.colors color: Nheko.colors.window flags: Qt.Tool | Qt.WindowStaysOnTopHint | Qt.WindowCloseButtonHint | Qt.WindowTitleHint - Component.onCompleted: Nheko.reparent(rawMessageRoot) Shortcut { sequence: StandardKey.Cancel diff --git a/resources/qml/dialogs/ReadReceipts.qml b/resources/qml/dialogs/ReadReceipts.qml
index aced4374..da87996e 100644 --- a/resources/qml/dialogs/ReadReceipts.qml +++ b/resources/qml/dialogs/ReadReceipts.qml
@@ -22,7 +22,6 @@ ApplicationWindow { palette: Nheko.colors color: Nheko.colors.window flags: Qt.Dialog | Qt.WindowCloseButtonHint | Qt.WindowTitleHint - Component.onCompleted: Nheko.reparent(readReceiptsRoot) Shortcut { sequence: StandardKey.Cancel diff --git a/resources/qml/dialogs/RoomDirectory.qml b/resources/qml/dialogs/RoomDirectory.qml
index f458ac51..36c29a0b 100644 --- a/resources/qml/dialogs/RoomDirectory.qml +++ b/resources/qml/dialogs/RoomDirectory.qml
@@ -22,7 +22,6 @@ ApplicationWindow { color: Nheko.colors.window modality: Qt.WindowModal flags: Qt.Dialog | Qt.WindowCloseButtonHint | Qt.WindowTitleHint - Component.onCompleted: Nheko.reparent(roomDirectoryWindow) title: qsTr("Explore Public Rooms") Shortcut { @@ -189,7 +188,6 @@ ApplicationWindow { Layout.fillWidth: true selectByMouse: true font.pixelSize: fontMetrics.font.pixelSize - padding: Nheko.paddingMedium color: Nheko.colors.text placeholderText: qsTr("Search for public rooms") onTextChanged: searchTimer.restart() @@ -200,7 +198,6 @@ ApplicationWindow { Layout.minimumWidth: 0.3 * header.width Layout.maximumWidth: 0.3 * header.width - padding: Nheko.paddingMedium color: Nheko.colors.text placeholderText: qsTr("Choose custom homeserver") onTextChanged: publicRooms.setMatrixServer(text) diff --git a/resources/qml/dialogs/RoomMembers.qml b/resources/qml/dialogs/RoomMembers.qml
index 89cce414..55d5488b 100644 --- a/resources/qml/dialogs/RoomMembers.qml +++ b/resources/qml/dialogs/RoomMembers.qml
@@ -24,7 +24,6 @@ ApplicationWindow { palette: Nheko.colors color: Nheko.colors.window flags: Qt.Dialog | Qt.WindowCloseButtonHint | Qt.WindowTitleHint - Component.onCompleted: Nheko.reparent(roomMembersRoot) Shortcut { sequence: StandardKey.Cancel diff --git a/resources/qml/dialogs/RoomSettings.qml b/resources/qml/dialogs/RoomSettings.qml
index c9f2b1a1..48d2e2b7 100644 --- a/resources/qml/dialogs/RoomSettings.qml +++ b/resources/qml/dialogs/RoomSettings.qml
@@ -23,7 +23,6 @@ ApplicationWindow { color: Nheko.colors.window modality: Qt.NonModal flags: Qt.Dialog | Qt.WindowCloseButtonHint | Qt.WindowTitleHint - Component.onCompleted: Nheko.reparent(roomSettingsDialog) title: qsTr("Room Settings") Shortcut { diff --git a/resources/qml/dialogs/UserProfile.qml b/resources/qml/dialogs/UserProfile.qml
index 29ce2c3f..73c4e68b 100644 --- a/resources/qml/dialogs/UserProfile.qml +++ b/resources/qml/dialogs/UserProfile.qml
@@ -13,9 +13,6 @@ import QtQuick.Window 2.13 import im.nheko 1.0 ApplicationWindow { - // this does not work in ApplicationWindow, just in Window - //transientParent: Nheko.mainwindow() - id: userProfileDialog property var profile @@ -29,7 +26,6 @@ ApplicationWindow { title: profile.isGlobalUserProfile ? qsTr("Global User Profile") : qsTr("Room User Profile") modality: Qt.NonModal flags: Qt.Dialog | Qt.WindowCloseButtonHint | Qt.WindowTitleHint - Component.onCompleted: Nheko.reparent(userProfileDialog) Shortcut { sequence: StandardKey.Cancel diff --git a/resources/qml/pages/LoginPage.qml b/resources/qml/pages/LoginPage.qml new file mode 100644
index 00000000..4d3a52b3 --- /dev/null +++ b/resources/qml/pages/LoginPage.qml
@@ -0,0 +1,182 @@ +// SPDX-FileCopyrightText: 2022 Nheko Contributors +// +// SPDX-License-Identifier: GPL-3.0-or-later + +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.2 +import QtQuick.Window 2.15 +import im.nheko 1.0 +import "../components/" +import "../ui/" +import "../" + +Item { + id: loginPage + property int maxExpansion: 400 + + property string error: login.error + + Login { + id: login + } + + ScrollView { + id: scroll + + clip: false + palette: Nheko.colors + ScrollBar.horizontal.visible: false + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + height: Math.min(loginPage.height, col.implicitHeight) + anchors.margins: Nheko.paddingLarge + + contentWidth: availableWidth + + ColumnLayout { + id: col + + spacing: Nheko.paddingMedium + + anchors.horizontalCenter: parent.horizontalCenter + width: Math.min(loginPage.maxExpansion, scroll.width- Nheko.paddingLarge*2) + + Image { + Layout.alignment: Qt.AlignHCenter + source: "qrc:/logos/login.png" + height: 128 + width: 128 + } + + RowLayout { + spacing: Nheko.paddingLarge + + Layout.fillWidth: true + MatrixTextField { + id: matrixIdLabel + label: qsTr("Matrix ID") + placeholderText: qsTr("e.g @joe:matrix.org") + onEditingFinished: login.mxid = text + + ToolTip.text: qsTr("Your login name. A mxid should start with @ followed by the user id. After the user id you need to include your server name after a :.\nYou can also put your homeserver address there, if your server doesn't support .well-known lookup.\nExample: @user:server.my\nIf Nheko fails to discover your homeserver, it will show you a field to enter the server manually.") + Keys.forwardTo: [pwBtn, ssoBtn] + } + + + Spinner { + height: matrixIdLabel.height/2 + Layout.alignment: Qt.AlignBottom + + visible: running + running: login.lookingUpHs + foreground: Nheko.colors.mid + } + } + + MatrixText { + textFormat: Text.PlainText + color: Nheko.theme.error + text: login.mxidError + visible: text + } + + MatrixTextField { + id: passwordLabel + Layout.fillWidth: true + label: qsTr("Password") + echoMode: TextInput.Password + ToolTip.text: qsTr("Your password.") + visible: login.passwordSupported + Keys.forwardTo: [pwBtn, ssoBtn] + } + + MatrixTextField { + id: deviceNameLabel + Layout.fillWidth: true + label: qsTr("Device name") + placeholderText: login.initialDeviceName() + ToolTip.text: qsTr("A name for this device, which will be shown to others, when verifying your devices. If none is provided a default is used.") + Keys.forwardTo: [pwBtn, ssoBtn] + } + + MatrixTextField { + id: hsLabel + enabled: visible + visible: login.homeserverNeeded + + Layout.fillWidth: true + label: qsTr("Homeserver address") + placeholderText: qsTr("server.my:8787") + text: login.homeserver + onEditingFinished: login.homeserver = text + ToolTip.text: qsTr("The address that can be used to contact you homeservers client API.\nExample: https://server.my:8787") + Keys.forwardTo: [pwBtn, ssoBtn] + } + + Item { + height: Nheko.avatarSize + Layout.fillWidth: true + + Spinner { + height: parent.height + anchors.centerIn: parent + + visible: running + running: login.loggingIn + foreground: Nheko.colors.mid + } + } + + MatrixText { + textFormat: Text.PlainText + color: Nheko.theme.error + text: loginPage.error + visible: text + } + + FlatButton { + id: pwBtn + visible: login.passwordSupported + enabled: login.homeserverValid && matrixIdLabel.text == login.mxid && login.homeserver == hsLabel.text + Layout.alignment: Qt.AlignHCenter + text: qsTr("LOGIN") + function pwLogin() { + login.onLoginButtonClicked(Login.Password, matrixIdLabel.text, passwordLabel.text, deviceNameLabel.text) + } + onClicked: pwBtn.pwLogin() + Keys.onEnterPressed: pwBtn.pwLogin() + Keys.onReturnPressed: pwBtn.pwLogin() + Keys.enabled: pwBtn.enabled && login.passwordSupported + } + FlatButton { + id: ssoBtn + visible: login.ssoSupported + enabled: login.homeserverValid && matrixIdLabel.text == login.mxid && login.homeserver == hsLabel.text + Layout.alignment: Qt.AlignHCenter + text: qsTr("SSO LOGIN") + function ssoLogin() { + login.onLoginButtonClicked(Login.SSO, matrixIdLabel.text, passwordLabel.text, deviceNameLabel.text) + } + onClicked: ssoBtn.ssoLogin() + Keys.onEnterPressed: ssoBtn.ssoLogin() + Keys.onReturnPressed: ssoBtn.ssoLogin() + Keys.enabled: ssoBtn.enabled && !login.passwordSupported + } + + } + } + + ImageButton { + anchors.top: parent.top + anchors.left: parent.left + anchors.margins: Nheko.paddingMedium + width: Nheko.avatarSize + height: Nheko.avatarSize + image: ":/icons/icons/ui/angle-arrow-left.svg" + ToolTip.visible: hovered + ToolTip.text: qsTr("Back") + onClicked: mainWindow.pop() + } +} diff --git a/resources/qml/pages/RegisterPage.qml b/resources/qml/pages/RegisterPage.qml new file mode 100644
index 00000000..44836ccb --- /dev/null +++ b/resources/qml/pages/RegisterPage.qml
@@ -0,0 +1,215 @@ +// SPDX-FileCopyrightText: 2022 Nheko Contributors +// +// SPDX-License-Identifier: GPL-3.0-or-later + +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.2 +import QtQuick.Window 2.15 +import im.nheko 1.0 +import "../components/" +import "../ui/" +import "../" + +Item { + id: registrationPage + property int maxExpansion: 400 + + property string error: regis.error + + Registration { + id: regis + } + + ScrollView { + id: scroll + + clip: false + palette: Nheko.colors + ScrollBar.horizontal.visible: false + anchors.left: parent.left + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + height: Math.min(registrationPage.height, col.implicitHeight) + anchors.margins: Nheko.paddingLarge + + contentWidth: availableWidth + + ColumnLayout { + id: col + + spacing: Nheko.paddingMedium + + anchors.horizontalCenter: parent.horizontalCenter + width: Math.min(registrationPage.maxExpansion, scroll.width- Nheko.paddingLarge*2) + + Image { + Layout.alignment: Qt.AlignHCenter + source: "qrc:/logos/login.png" + height: 128 + width: 128 + } + + RowLayout { + spacing: Nheko.paddingLarge + + Layout.fillWidth: true + MatrixTextField { + id: hsLabel + label: qsTr("Homeserver") + placeholderText: qsTr("your.server") + onEditingFinished: regis.setServer(text) + + ToolTip.text: qsTr("A server that allows registration. Since matrix is decentralized, you need to first find a server you can register on or host your own.") + } + + + Spinner { + height: hsLabel.height/2 + Layout.alignment: Qt.AlignBottom + + visible: running + running: regis.lookingUpHs + foreground: Nheko.colors.mid + } + } + + MatrixText { + textFormat: Text.PlainText + color: Nheko.theme.error + text: regis.hsError + visible: text + } + + RowLayout { + spacing: Nheko.paddingLarge + + visible: regis.supported + + Layout.fillWidth: true + MatrixTextField { + id: usernameLabel + Layout.fillWidth: true + label: qsTr("Username") + ToolTip.text: qsTr("The username must not be empty, and must contain only the characters a-z, 0-9, ., _, =, -, and /.") + onEditingFinished: regis.checkUsername(text) + } + Spinner { + height: usernameLabel.height/2 + Layout.alignment: Qt.AlignBottom + + visible: running + running: regis.lookingUpUsername + foreground: Nheko.colors.mid + } + + Image { + width: usernameLabel.height/2 + height: width + Layout.preferredHeight: usernameLabel.height/2 + Layout.preferredWidth: usernameLabel.height/2 + Layout.alignment: Qt.AlignBottom + source: regis.usernameAvailable ? ("image://colorimage/:/icons/icons/ui/checkmark.svg?green") : ("image://colorimage/:/icons/icons/ui/dismiss.svg?"+Nheko.theme.error) + visible: regis.usernameAvailable || regis.usernameUnavailable + ToolTip.visible: ma.hovered + ToolTip.text: qsTr("Back") + sourceSize.height: height * Screen.devicePixelRatio + sourceSize.width: width * Screen.devicePixelRatio + HoverHandler { + id: ma + } + } + } + + MatrixText { + textFormat: Text.PlainText + color: Nheko.theme.error + text: regis.usernameError + visible: text + } + + + MatrixTextField { + visible: regis.supported + id: passwordLabel + Layout.fillWidth: true + label: qsTr("Password") + echoMode: TextInput.Password + ToolTip.text: qsTr("Please choose a secure password. The exact requirements for password strength may depend on your server.") + } + + MatrixTextField { + visible: regis.supported + id: passwordConfirmationLabel + Layout.fillWidth: true + label: qsTr("Password confirmation") + echoMode: TextInput.Password + } + + MatrixText { + visible: regis.supported + textFormat: Text.PlainText + color: Nheko.theme.error + text: passwordLabel.text != passwordConfirmationLabel.text ? qsTr("Your passwords do not match!") : "" + } + + MatrixTextField { + visible: regis.supported + id: deviceNameLabel + Layout.fillWidth: true + label: qsTr("Device name") + placeholderText: regis.initialDeviceName() + ToolTip.text: qsTr("A name for this device, which will be shown to others, when verifying your devices. If none is provided a default is used.") + } + + Item { + height: Nheko.avatarSize + Layout.fillWidth: true + + Spinner { + height: parent.height + anchors.centerIn: parent + + visible: running + running: regis.registering + foreground: Nheko.colors.mid + } + } + + MatrixText { + textFormat: Text.PlainText + color: Nheko.theme.error + text: registrationPage.error + visible: text + } + + FlatButton { + id: regisBtn + visible: regis.supported + enabled: usernameLabel.text && passwordLabel.text && passwordLabel.text == passwordConfirmationLabel.text + Layout.alignment: Qt.AlignHCenter + text: qsTr("REGISTER") + function register() { + regis.startRegistration(usernameLabel.text, passwordLabel.text, deviceNameLabel.text) + } + onClicked: regisBtn.register() + Keys.onEnterPressed: regisBtn.register() + Keys.onReturnPressed: regisBtn.register() + Keys.enabled: regisBtn.enabled && regis.supported + } + } + } + + ImageButton { + anchors.top: parent.top + anchors.left: parent.left + anchors.margins: Nheko.paddingMedium + width: Nheko.avatarSize + height: Nheko.avatarSize + image: ":/icons/icons/ui/angle-arrow-left.svg" + ToolTip.visible: hovered + ToolTip.text: qsTr("Back") + onClicked: mainWindow.pop() + } +} + diff --git a/resources/qml/pages/WelcomePage.qml b/resources/qml/pages/WelcomePage.qml new file mode 100644
index 00000000..e1ecc31d --- /dev/null +++ b/resources/qml/pages/WelcomePage.qml
@@ -0,0 +1,73 @@ +// SPDX-FileCopyrightText: 2022 Nheko Contributors +// +// SPDX-License-Identifier: GPL-3.0-or-later + +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.2 +import QtQuick.Window 2.15 +import im.nheko 1.0 +import "../components/" + +ColumnLayout { + Item { + Layout.fillHeight: true + } + + Image { + Layout.alignment: Qt.AlignHCenter + source: "qrc:/logos/splash.png" + height: 256 + width: 256 + } + + Label { + Layout.margins: Nheko.paddingLarge + Layout.bottomMargin: 0 + Layout.alignment: Qt.AlignHCenter + Layout.fillWidth: true + text: qsTr("Welcome to nheko! The desktop client for the Matrix protocol.") + color: Nheko.colors.text + font.pointSize: fontMetrics.font.pointSize*2 + wrapMode: Text.Wrap + horizontalAlignment: Text.AlignHCenter + } + Label { + Layout.margins: Nheko.paddingLarge + Layout.alignment: Qt.AlignHCenter + Layout.fillWidth: true + text: qsTr("Enjoy your stay!") + color: Nheko.colors.text + font.pointSize: fontMetrics.font.pointSize*1.5 + wrapMode: Text.Wrap + horizontalAlignment: Text.AlignHCenter + } + + RowLayout { + Item { + Layout.fillWidth: true + } + FlatButton { + Layout.margins: Nheko.paddingLarge + Layout.alignment: Qt.AlignHCenter + text: qsTr("REGISTER") + onClicked: { + mainWindow.push(registerPage); + } + } + FlatButton { + Layout.margins: Nheko.paddingLarge + Layout.alignment: Qt.AlignHCenter + text: qsTr("LOGIN") + onClicked: { + mainWindow.push(loginPage); + } + } + Item { + Layout.fillWidth: true + } + } + Item { + Layout.fillHeight: true + } +} diff --git a/resources/qml/ui/Snackbar.qml b/resources/qml/ui/Snackbar.qml new file mode 100644
index 00000000..80c0d888 --- /dev/null +++ b/resources/qml/ui/Snackbar.qml
@@ -0,0 +1,98 @@ +// SPDX-FileCopyrightText: 2022 Nheko Contributors +// +// SPDX-License-Identifier: GPL-3.0-or-later + +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import im.nheko 1.0 + +Popup { + id: snackbar + + property var messages: [] + property string currentMessage: "" + + function showNotification(msg) { + messages.push(msg); + currentMessage = messages[0]; + if (!visible) { + open(); + dismissTimer.start(); + } + } + + Timer { + id: dismissTimer + interval: 10000 + onTriggered: snackbar.close() + } + + onAboutToHide: { + messages.shift(); + } + onClosed: { + if (messages.length > 0) { + currentMessage = messages[0]; + open(); + dismissTimer.restart(); + } + } + + parent: Overlay.overlay + opacity: 0 + y: -100 + x: (parent.width - width)/2 + padding: Nheko.paddingLarge + + contentItem: Label { + color: Nheko.colors.light + width: Math.max(Overlay.overlay? Overlay.overlay.width/2 : 0, 400) + text: snackbar.currentMessage + font.bold: true + } + + background: Rectangle { + radius: Nheko.paddingLarge + color: Nheko.colors.dark + opacity: 0.8 + } + + enter: Transition { + NumberAnimation { + target: snackbar + property: "opacity" + from: 0.0 + to: 1.0 + duration: 200 + easing.type: Easing.OutCubic + } + NumberAnimation { + target: snackbar + properties: "y" + from: -100 + to: 100 + duration: 1000 + easing.type: Easing.OutCubic + } + } + exit: Transition { + NumberAnimation { + target: snackbar + property: "opacity" + from: 1.0 + to: 0.0 + duration: 300 + easing.type: Easing.InCubic + } + NumberAnimation { + target: snackbar + properties: "y" + to: -100 + from: 100 + duration: 300 + easing.type: Easing.InCubic + } + } +} + + diff --git a/resources/res.qrc b/resources/res.qrc
index a2ee393f..2fba5f4c 100644 --- a/resources/res.qrc +++ b/resources/res.qrc
@@ -110,6 +110,9 @@ <file>qml/TypingIndicator.qml</file> <file>qml/NotificationWarning.qml</file> <file>qml/pages/UserSettingsPage.qml</file> + <file>qml/pages/WelcomePage.qml</file> + <file>qml/pages/LoginPage.qml</file> + <file>qml/pages/RegisterPage.qml</file> <file>qml/components/AdaptiveLayout.qml</file> <file>qml/components/AdaptiveLayoutElement.qml</file> <file>qml/components/AvatarListTile.qml</file> @@ -154,6 +157,7 @@ <file>qml/ui/NhekoSlider.qml</file> <file>qml/ui/Ripple.qml</file> <file>qml/ui/Spinner.qml</file> + <file>qml/ui/Snackbar.qml</file> <file>qml/ui/animations/BlinkAnimation.qml</file> <file>qml/ui/media/MediaControls.qml</file> <file>qml/voip/ActiveCallBar.qml</file>