From 46e685847f7f4831c8c3ef486987eae7378e3032 Mon Sep 17 00:00:00 2001 From: miruka Date: Wed, 21 Aug 2019 04:39:07 -0400 Subject: [PATCH] Replace HInteractiveRectangle by HTiledelegate --- TODO.md | 2 +- src/qml/Base/HButton.qml | 5 + src/qml/Base/HFixedListView.qml | 3 +- src/qml/Base/HTileDelegate.qml | 101 +++++++++++ src/qml/Chat/RoomSidePane/MemberDelegate.qml | 42 ++--- src/qml/Chat/RoomSidePane/MembersView.qml | 5 +- src/qml/SidePane/AccountRoomList.qml | 2 +- src/qml/SidePane/DelegateAccount.qml | 140 +++++---------- src/qml/SidePane/DelegateRoom.qml | 176 +++++-------------- src/themes/Default.qpl | 15 +- 10 files changed, 215 insertions(+), 276 deletions(-) create mode 100644 src/qml/Base/HTileDelegate.qml diff --git a/TODO.md b/TODO.md index 22e4c8f0..fb144411 100644 --- a/TODO.md +++ b/TODO.md @@ -1,6 +1,5 @@ - Refactoring - Use HInterfaceBox for EditAccount Profile and Encryption - - Use ItemDelegate - Make all icon SVG files white/black, since we can now use ColorOverlay - Make the icon blue in EditAccount when hovering and no avatar set @@ -12,6 +11,7 @@ - Room Sidepane - Hide when window too small - Also save/load its size + - Is auto-sizing actually needed, or can we just set a default manual size? - When qml syntax highlighting supports ES6 string interpolation, use them - Fixes diff --git a/src/qml/Base/HButton.qml b/src/qml/Base/HButton.qml index d2942cc9..35df7aa5 100644 --- a/src/qml/Base/HButton.qml +++ b/src/qml/Base/HButton.qml @@ -4,6 +4,11 @@ import QtQuick.Layouts 1.12 Button { id: button + spacing: theme.spacing + leftPadding: spacing / 1.5 + rightPadding: spacing / 1.5 + topPadding: spacing / 2 + bottomPadding: spacing / 2 opacity: enabled ? 1 : theme.disabledElementsOpacity onVisibleChanged: if (! visible) loading = false diff --git a/src/qml/Base/HFixedListView.qml b/src/qml/Base/HFixedListView.qml index 253de681..2994cb1d 100644 --- a/src/qml/Base/HFixedListView.qml +++ b/src/qml/Base/HFixedListView.qml @@ -18,8 +18,7 @@ ListView { highlight: HRectangle { - color: theme.controls.interactiveRectangle.checkedOverlay - opacity: theme.controls.interactiveRectangle.checkedOpacity + color: theme.controls.button.checkedOverlay } // Important: diff --git a/src/qml/Base/HTileDelegate.qml b/src/qml/Base/HTileDelegate.qml new file mode 100644 index 00000000..2e669080 --- /dev/null +++ b/src/qml/Base/HTileDelegate.qml @@ -0,0 +1,101 @@ +import QtQuick 2.12 +import QtQuick.Layouts 1.12 + +HButton { + id: tile + + + signal activated() + signal highlightMe() + + + property bool isCurrent: false + + readonly property var delegateModel: model + + default property var additionalItems: [] + + readonly property alias title: title + readonly property alias additionalInfo: additionalInfo + readonly property alias rightInfo: rightInfo + readonly property alias subtitle: subtitle + + property Item image + + property Item details: HColumnLayout { + Layout.fillWidth: true + + HRowLayout { + spacing: tile.spacing + + HLabel { + id: title + text: "Title" + elide: Text.ElideRight + verticalAlignment: Qt.AlignVCenter + + Layout.fillWidth: true + } + + HRowLayout { + id: additionalInfo + } + + HLabel { + id: rightInfo + font.pixelSize: theme.fontSize.small + + visible: Layout.maximumWidth > 0 + Layout.maximumWidth: + text && tile.width >= 200 ? implicitWidth : 0 + + Behavior on Layout.maximumWidth { HNumberAnimation {} } + } + } + + HRichLabel { + id: subtitle + textFormat: Text.StyledText + font.pixelSize: theme.fontSize.small + elide: Text.ElideRight + + visible: Layout.maximumHeight > 0 + Layout.maximumHeight: text ? implicitWidth : 0 + Layout.fillWidth: true + + Behavior on Layout.maximumHeight { HNumberAnimation {} } + } + } + + + contentItem: HRowLayout { + spacing: tile.spacing + children: [image, details].concat(additionalItems) + } + + onIsCurrentChanged: if (isCurrent) highlightMe() + onHighlightMe: accountRoomList.currentIndex = model.index + + onClicked: { + ListView.highlightRangeMode = ListView.NoHighlightRange + ListView.highlightMoveDuration = 0 + activated() + ListView.highlightRangeMode = ListView.ApplyRange + ListView.highlightMoveDuration = theme.animationDuration + } + + + Timer { + interval: 100 + repeat: true + running: ListView.currentIndex == -1 + // Component.onCompleted won't work for this + onTriggered: if (isCurrent) highlightMe() + } + + // Connections { + // target: ListView + // onHideHoverHighlight: tile.hovered = false + // } + +} diff --git a/src/qml/Chat/RoomSidePane/MemberDelegate.qml b/src/qml/Chat/RoomSidePane/MemberDelegate.qml index 4ad15c0a..b32d15af 100644 --- a/src/qml/Chat/RoomSidePane/MemberDelegate.qml +++ b/src/qml/Chat/RoomSidePane/MemberDelegate.qml @@ -1,38 +1,18 @@ import QtQuick 2.12 -import QtQuick.Layouts 1.12 import "../../Base" -import "../../utils.js" as Utils -HInteractiveRectangle { +HTileDelegate { id: memberDelegate - width: memberList.width - height: rowLayout.height + spacing: roomSidePane.currentSpacing + rightPadding: 0 + backgroundColor: theme.sidePane.member.background - HRowLayout { - id: rowLayout - x: roomSidePane.currentSpacing - width: parent.width - roomSidePane.currentSpacing * 1.5 - height: avatar.height + roomSidePane.currentSpacing / 1.5 - spacing: roomSidePane.currentSpacing - - HUserAvatar { - id: avatar - userId: model.user_id - displayName: model.display_name - avatarUrl: model.avatar_url - } - - HColumnLayout { - Layout.fillWidth: true - - HLabel { - id: memberName - text: model.display_name || model.user_id - elide: Text.ElideRight - verticalAlignment: Qt.AlignVCenter - - Layout.fillWidth: true - } - } + image: HUserAvatar { + userId: model.user_id + displayName: model.display_name + avatarUrl: model.avatar_url } + + title.color: theme.sidePane.member.name + title.text: model.display_name || model.user_id } diff --git a/src/qml/Chat/RoomSidePane/MembersView.qml b/src/qml/Chat/RoomSidePane/MembersView.qml index 9373aabe..b8119f21 100644 --- a/src/qml/Chat/RoomSidePane/MembersView.qml +++ b/src/qml/Chat/RoomSidePane/MembersView.qml @@ -6,7 +6,6 @@ import "../../utils.js" as Utils HColumnLayout { HListView { id: memberList - bottomMargin: currentSpacing model: HListModel { keyField: "user_id" @@ -16,7 +15,9 @@ HColumnLayout { ) } - delegate: MemberDelegate {} + delegate: MemberDelegate { + width: memberList.width + } Layout.fillWidth: true Layout.fillHeight: true diff --git a/src/qml/SidePane/AccountRoomList.qml b/src/qml/SidePane/AccountRoomList.qml index 84e8c87b..60b6791a 100644 --- a/src/qml/SidePane/AccountRoomList.qml +++ b/src/qml/SidePane/AccountRoomList.qml @@ -75,7 +75,7 @@ HListView { } function activate() { - currentItem.item.activate() + currentItem.item.activated() } function toggleCollapseAccount() { diff --git a/src/qml/SidePane/DelegateAccount.qml b/src/qml/SidePane/DelegateAccount.qml index 1f862cb1..936bd414 100644 --- a/src/qml/SidePane/DelegateAccount.qml +++ b/src/qml/SidePane/DelegateAccount.qml @@ -2,21 +2,24 @@ import QtQuick 2.12 import QtQuick.Layouts 1.12 import "../Base" -HInteractiveRectangle { +HTileDelegate { id: accountDelegate - color: theme.sidePane.account.background - // checked: isCurrent - height: row.height + spacing: 0 + topPadding: model.index > 0 ? sidePane.currentSpacing / 2 : 0 + bottomPadding: topPadding + backgroundColor: theme.sidePane.account.background + + opacity: collapsed && ! forceExpand ? + theme.sidePane.account.collapsedOpacity : 1 + + isCurrent: window.uiState.page == "Pages/EditAccount/EditAccount.qml" && + window.uiState.pageProperties.userId == model.data.user_id - readonly property var delegateModel: model + Behavior on opacity { HNumberAnimation {} } - readonly property bool isCurrent: - window.uiState.page == "Pages/EditAccount/EditAccount.qml" && - window.uiState.pageProperties.userId == model.data.user_id - readonly property bool forceExpand: - Boolean(accountRoomList.filter) + readonly property bool forceExpand: Boolean(accountRoomList.filter) // Hide harmless error when a filter matches nothing readonly property bool collapsed: try { @@ -24,109 +27,50 @@ HInteractiveRectangle { } catch (err) {} - onIsCurrentChanged: if (isCurrent) beHighlighted() + onActivated: pageLoader.showPage( + "EditAccount/EditAccount", { "userId": model.data.user_id } + ) - function beHighlighted() { - accountRoomList.currentIndex = model.index - } - function toggleCollapse() { window.uiState.collapseAccounts[model.data.user_id] = ! collapsed window.uiStateChanged() } - function activate() { - pageLoader.showPage( - "EditAccount/EditAccount", { "userId": model.data.user_id } - ) + + image: HUserAvatar { + userId: model.data.user_id + displayName: model.data.display_name + avatarUrl: model.data.avatar_url } + title.color: theme.sidePane.account.name + title.text: model.data.display_name || model.data.user_id + title.font.pixelSize: theme.fontSize.big + title.leftPadding: sidePane.currentSpacing - // Component.onCompleted won't work for this - Timer { - interval: 100 - repeat: true - running: accountRoomList.currentIndex == -1 - onTriggered: if (isCurrent) beHighlighted() - } + HButton { + id: expand + iconName: "expand" + ico.dimension: 16 + backgroundColor: "transparent" + leftPadding: sidePane.currentSpacing / 1.5 + rightPadding: leftPadding + onClicked: accountDelegate.toggleCollapse() - Connections { - target: accountRoomList - onHideHoverHighlight: accountDelegate.hovered = false - } + visible: opacity > 0 + opacity: accountDelegate.forceExpand ? 0 : 1 - TapHandler { - onTapped: { - accountRoomList.highlightRangeMode = ListView.NoHighlightRange - accountRoomList.highlightMoveDuration = 0 - activate() - accountRoomList.highlightRangeMode = ListView.ApplyRange - accountRoomList.highlightMoveDuration = theme.animationDuration - } - } + ico.transform: Rotation { + origin.x: expand.ico.dimension / 2 + origin.y: expand.ico.dimension / 2 - HRowLayout { - id: row - width: parent.width - - HUserAvatar { - id: avatar - userId: model.data.user_id - displayName: model.data.display_name - avatarUrl: model.data.avatar_url - - opacity: collapsed && ! forceExpand ? - theme.sidePane.account.collapsedOpacity : 1 - Behavior on opacity { HNumberAnimation {} } - - Layout.topMargin: model.index > 0 ? sidePane.currentSpacing / 2 : 0 - Layout.bottomMargin: Layout.topMargin + angle: collapsed ? 180 : 90 + Behavior on angle { HNumberAnimation {} } } - HLabel { - id: accountLabel - color: theme.sidePane.account.name - text: model.data.display_name || model.data.user_id - font.pixelSize: theme.fontSize.big - elide: HLabel.ElideRight + Behavior on opacity { HNumberAnimation {} } - leftPadding: sidePane.currentSpacing - verticalAlignment: Text.AlignVCenter - - opacity: collapsed && ! forceExpand ? - theme.sidePane.account.collapsedOpacity : 1 - Behavior on opacity { HNumberAnimation {} } - - Layout.fillWidth: true - Layout.fillHeight: true - } - - HButton { - id: expandButton - iconName: "expand" - ico.dimension: 16 - backgroundColor: "transparent" - leftPadding: sidePane.currentSpacing - rightPadding: leftPadding - onClicked: accountDelegate.toggleCollapse() - - visible: opacity > 0 - opacity: - accountDelegate.forceExpand ? 0 : - collapsed ? theme.sidePane.account.collapsedOpacity + 0.2 : - 1 - Behavior on opacity { HNumberAnimation {} } - - ico.transform: Rotation { - origin.x: expandButton.ico.dimension / 2 - origin.y: expandButton.ico.dimension / 2 - - angle: collapsed ? 180 : 90 - Behavior on angle { HNumberAnimation {} } - } - - Layout.fillHeight: true - } + Layout.fillHeight: true } } diff --git a/src/qml/SidePane/DelegateRoom.qml b/src/qml/SidePane/DelegateRoom.qml index 3a9bb40a..708e8f0e 100644 --- a/src/qml/SidePane/DelegateRoom.qml +++ b/src/qml/SidePane/DelegateRoom.qml @@ -3,157 +3,73 @@ import QtQuick.Layouts 1.12 import "../Base" import "../utils.js" as Utils -HInteractiveRectangle { +HTileDelegate { id: roomDelegate - color: theme.sidePane.room.background - visible: height > 0 - height: rowLayout.height + spacing: sidePane.currentSpacing + backgroundColor: theme.sidePane.room.background opacity: model.data.left ? theme.sidePane.room.leftRoomOpacity : 1 + isCurrent: window.uiState.page == "Chat/Chat.qml" && + window.uiState.pageProperties.userId == model.user_id && + window.uiState.pageProperties.roomId == model.data.room_id Behavior on opacity { HNumberAnimation {} } - readonly property var delegateModel: model - - readonly property bool forceExpand: - Boolean(accountRoomList.filter) - - readonly property bool isCurrent: - window.uiState.page == "Chat/Chat.qml" && - window.uiState.pageProperties.userId == model.user_id && - window.uiState.pageProperties.roomId == model.data.room_id + readonly property var eventDate: + model.data.last_event ? model.data.last_event.date : null - onIsCurrentChanged: if (isCurrent) beHighlighted() + onActivated: pageLoader.showRoom(model.user_id, model.data.room_id) - function beHighlighted() { - accountRoomList.currentIndex = model.index + image: HRoomAvatar { + displayName: model.data.display_name + avatarUrl: model.data.avatar_url } - function activate() { - pageLoader.showRoom(model.user_id, model.data.room_id) + title.color: theme.sidePane.room.name + title.text: model.data.display_name || "Empty room" + title.textFormat: model.data.display_name? Text.PlainText : Text.StyledText + + additionalInfo.children: HIcon { + svgName: "invite-received" + + visible: Layout.maximumWidth > 0 + Layout.maximumWidth: + model.data.inviter_id && ! model.data.left ? + implicitWidth : 0 + + Behavior on Layout.maximumWidth { HNumberAnimation {} } } + rightInfo.color: theme.sidePane.room.lastEventDate + rightInfo.text: { + ! eventDate ? "" : - // Component.onCompleted won't work for this - Timer { - interval: 100 - repeat: true - running: accountRoomList.currentIndex == -1 - onTriggered: if (isCurrent) beHighlighted() + Utils.dateIsToday(eventDate) ? + Utils.formatTime(eventDate, false) : // no seconds + + eventDate.getFullYear() == new Date().getFullYear() ? + Qt.formatDate(eventDate, "d MMM") : // e.g. "5 Dec" + + eventDate.getFullYear() } - Connections { - target: accountRoomList - onHideHoverHighlight: roomDelegate.hovered = false - } + subtitle.color: theme.sidePane.room.subtitle + subtitle.textFormat: Text.StyledText + subtitle.text: { + if (! model.data.last_event) { return "" } - TapHandler { - onTapped: { - accountRoomList.highlightRangeMode = ListView.NoHighlightRange - accountRoomList.highlightMoveDuration = 0 - activate() - accountRoomList.highlightRangeMode = ListView.ApplyRange - accountRoomList.highlightMoveDuration = theme.animationDuration - } - } + let ev = model.data.last_event - HRowLayout { - id: rowLayout - - spacing: sidePane.currentSpacing - x: sidePane.currentSpacing - width: parent.width - sidePane.currentSpacing * 1.75 - height: roomName.height + subtitle.height + sidePane.currentSpacing - - HRoomAvatar { - id: roomAvatar - displayName: model.data.display_name - avatarUrl: model.data.avatar_url + if (ev.event_type === "RoomMessageEmote" || + ! ev.event_type.startsWith("RoomMessage")) { + return Utils.processedEventText(ev) } - HColumnLayout { - Layout.fillWidth: true - - HRowLayout { - spacing: rowLayout.spacing - - HLabel { - id: roomName - color: theme.sidePane.room.name - text: model.data.display_name || "Empty room" - textFormat: - model.data.display_name? - Text.PlainText : Text.StyledText - elide: Text.ElideRight - verticalAlignment: Qt.AlignVCenter - - Layout.fillWidth: true - } - - HIcon { - svgName: "invite-received" - - visible: Layout.maximumWidth > 0 - Layout.maximumWidth: - model.data.inviter_id && ! model.data.left ? - implicitWidth : 0 - Behavior on Layout.maximumWidth { HNumberAnimation {} } - } - - HLabel { - readonly property var evDate: - model.data.last_event ? - model.data.last_event.date : null - - id: lastEventDate - font.pixelSize: theme.fontSize.small - color: theme.sidePane.room.lastEventDate - - text: ! evDate ? "" : - - Utils.dateIsToday(evDate) ? - Utils.formatTime(evDate, false) : // no seconds - - evDate.getFullYear() == new Date().getFullYear() ? - Qt.formatDate(evDate, "d MMM") : // e.g. "5 Dec" - - evDate.getFullYear() - - visible: Layout.maximumWidth > 0 - Layout.maximumWidth: - text && roomDelegate.width >= 200 ? implicitWidth : 0 - Behavior on Layout.maximumWidth { HNumberAnimation {} } - } - } - - HRichLabel { - id: subtitle - color: theme.sidePane.room.subtitle - visible: Boolean(text) - textFormat: Text.StyledText - font.pixelSize: theme.fontSize.small - elide: Text.ElideRight - - text: { - if (! model.data.last_event) { return "" } - - let ev = model.data.last_event - - if (ev.event_type === "RoomMessageEmote" || - ! ev.event_type.startsWith("RoomMessage")) { - return Utils.processedEventText(ev) - } - - return Utils.coloredNameHtml( - ev.sender_name, ev.sender_id - ) + ": " + ev.inline_content - } - - Layout.fillWidth: true - } - } + return Utils.coloredNameHtml( + ev.sender_name, ev.sender_id + ) + ": " + ev.inline_content } } diff --git a/src/themes/Default.qpl b/src/themes/Default.qpl index 875737b0..9d8a7d43 100644 --- a/src/themes/Default.qpl +++ b/src/themes/Default.qpl @@ -106,17 +106,6 @@ controls: color text: colors.text - interactiveRectangle: - color background: "transparent" - - color hoveredOverlay: hsluv(0, 0, 50) - color pressedOverlay: hsluv(0, 0, 50) - color checkedOverlay: hsluv(0, 0, 50) - - real hoveredOpacity: 0.3 - real pressedOpacity: 0.2 - real checkedOpacity: 0.2 - textField: color background: colors.inputBackground color focusedBackground: background @@ -184,6 +173,10 @@ sidePane: color subtitle: colors.dimText color lastEventDate: colors.halfDimText + member: + color background: "transparent" + color name: colors.text + settingsButton: color background: colors.inputBackground