Restyle the chat UI

This commit is contained in:
miruka 2019-04-28 11:01:38 -04:00
parent f65ea9dd0d
commit 5650234e3b
21 changed files with 182 additions and 77 deletions

View File

@ -6,6 +6,7 @@
- Better names and organization for the Message components - Better names and organization for the Message components
- Bug fixes - Bug fixes
- 100% CPU usage when hitting top edge to trigger messages loading
- Fix tooltip hide() - Fix tooltip hide()
- Sending `![A picture](https://picsum.photos/256/256)` → not clickable? - Sending `![A picture](https://picsum.photos/256/256)` → not clickable?
- Icons aren't reloaded - Icons aren't reloaded
@ -13,7 +14,10 @@
- HStyle singleton isn't reloaded - HStyle singleton isn't reloaded
- UI - UI
- Server selection
- Register/Forgot? for SignIn dialog - Register/Forgot? for SignIn dialog
- Scaling
- See [Text.fontSizeMode](https://doc.qt.io/qt-5/qml-qtquick-text.html#fontSizeMode-prop)
- Test HGlassRectangle elements when no effects are available - Test HGlassRectangle elements when no effects are available
- Leave room - Leave room
- Forget room warning popup - Forget room warning popup

View File

@ -1,6 +1,7 @@
import QtQuick 2.7 import QtQuick 2.7
import QtQuick.Controls 2.0 import QtQuick.Controls 2.0
import QtQuick.Layouts 1.4 import QtQuick.Layouts 1.4
import "../base" as Base
Item { Item {
property bool invisible: false property bool invisible: false
@ -22,13 +23,18 @@ Item {
anchors.fill: parent anchors.fill: parent
visible: ! invisible && imageSource === null visible: ! invisible && imageSource === null
color: resolvedName === "?" ? color: resolvedName === "?" ?
Qt.hsla(0, 0, 0.22, 1) : Base.HStyle.avatar.background.unknown :
Qt.hsla(Backend.hueFromString(resolvedName), 0.22, 0.5, 1) Qt.hsla(
Backend.hueFromString(resolvedName),
Base.HStyle.avatar.background.saturation,
Base.HStyle.avatar.background.lightness,
Base.HStyle.avatar.background.alpha
)
HLabel { HLabel {
anchors.centerIn: parent anchors.centerIn: parent
text: resolvedName.charAt(0) text: resolvedName.charAt(0)
color: "white" color: Base.HStyle.avatar.letter
font.pixelSize: letterRectangle.height / 1.4 font.pixelSize: letterRectangle.height / 1.4
} }
} }

View File

@ -2,6 +2,8 @@ import QtQuick 2.7
import QtGraphicalEffects 1.0 import QtGraphicalEffects 1.0
Item { Item {
property bool isPageStackDescendant: true
default property alias children: rectangle.children default property alias children: rectangle.children
property alias color: rectangle.color property alias color: rectangle.color
property alias gradient: rectangle.gradient property alias gradient: rectangle.gradient
@ -14,16 +16,18 @@ Item {
sourceItem: mainUIBackground sourceItem: mainUIBackground
anchors.fill: parent anchors.fill: parent
sourceRect: Qt.rect( sourceRect: Qt.rect(
pageStack.x + parent.x, pageStack.y + parent.y, width, height (isPageStackDescendant ? pageStack.x : 0) + parent.x,
(isPageStackDescendant ? pageStack.y : 0) + parent.y,
width,
height
) )
} }
FastBlur { FastBlur {
id: fastBlur id: fastBlur
cached: true
anchors.fill: effectSource anchors.fill: effectSource
source: effectSource source: effectSource
radius: 8 radius: rectangle.color == "#00000000" ? 0 : 8
} }
Rectangle { Rectangle {

View File

@ -0,0 +1,31 @@
import QtQuick 2.7
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.4
import "../base" as Base
Base.HRowLayout {
property alias text: noticeLabel.text
property alias color: noticeLabel.color
property alias font: noticeLabel.font
property alias backgroundColor: noticeLabelBackground.color
property alias radius: noticeLabelBackground.radius
Base.HLabel {
id: noticeLabel
horizontalAlignment: Text.AlignHCenter
wrapMode: Text.Wrap
padding: 3
leftPadding: 10
rightPadding: 10
Layout.margins: 10
Layout.alignment: Qt.AlignCenter
Layout.maximumWidth: parent.width - Layout.margins * 2
background: Rectangle {
id: noticeLabelBackground
color: Base.HStyle.box.background
radius: Base.HStyle.box.radius
}
}
}

View File

@ -8,7 +8,7 @@ HGlassRectangle {
readonly property int baseWidth: baseHeight * widthForHeight readonly property int baseWidth: baseHeight * widthForHeight
readonly property int margins: baseHeight * 0.03 readonly property int margins: baseHeight * 0.03
color: HStyle.boxes.background color: HStyle.box.background
height: Math.min(parent.height, baseHeight) height: Math.min(parent.height, baseHeight)
width: Math.min(parent.width, baseWidth) width: Math.min(parent.width, baseWidth)
scale: Math.max(1, parent.height / startScalingUpAboveHeight) scale: Math.max(1, parent.height / startScalingUpAboveHeight)

View File

@ -2,6 +2,8 @@ pragma Singleton
import QtQuick 2.7 import QtQuick 2.7
QtObject { QtObject {
id: style
readonly property QtObject fontSize: QtObject { readonly property QtObject fontSize: QtObject {
property int smallest: 6 property int smallest: 6
property int smaller: 8 property int smaller: 8
@ -19,19 +21,78 @@ QtObject {
} }
readonly property QtObject colors: QtObject { readonly property QtObject colors: QtObject {
property color background0: Qt.hsla(1, 1, 1, 0.4) property color background0: Qt.hsla(0, 0, 0.8, 0.7)
property color foreground: "black"
property color foregroundDim: Qt.hsla(0, 0, 0.2, 1)
property color foregroundError: Qt.hsla(0.95, 0.64, 0.32, 1)
} }
property int radius: 5
readonly property QtObject sidePane: QtObject { readonly property QtObject sidePane: QtObject {
property color background: colors.background0 property color background: colors.background0
} }
readonly property QtObject boxes: QtObject { readonly property QtObject chat: QtObject {
property color background: colors.background0 readonly property QtObject roomHeader: QtObject {
property int radius: 5 property color background: colors.background0
}
readonly property QtObject messageList: QtObject {
property color background: colors.background0
}
readonly property QtObject message: QtObject {
property color background: colors.background0
property color body: colors.foreground
property color date: colors.foregroundDim
}
readonly property QtObject event: QtObject {
property color background: colors.background0
property real saturation: 0.22
property real lightness: 0.24
property color date: colors.foregroundDim
}
readonly property QtObject daybreak: QtObject {
property color background: colors.background0
property color foreground: colors.foreground
property int radius: style.radius
}
readonly property QtObject inviteBanner: QtObject {
property color background: colors.background0
}
readonly property QtObject leftBanner: QtObject {
property color background: colors.background0
}
readonly property QtObject sendBox: QtObject {
property color background: colors.background0
}
} }
readonly property QtObject avatars: QtObject { readonly property QtObject box: QtObject {
property int radius: 5 property color background: colors.background0
property int radius: style.radius
}
readonly property QtObject avatar: QtObject {
property int radius: style.radius
property color letter: "white"
readonly property QtObject background: QtObject {
property real saturation: 0.22
property real lightness: 0.5
property real alpha: 1
property color unknown: Qt.hsla(0, 0, 0.22, 1)
}
}
readonly property QtObject displayName: QtObject {
property real saturation: 0.32
property real lightness: 0.3
} }
} }

View File

@ -3,11 +3,10 @@ import QtQuick.Controls 2.2
import QtQuick.Layouts 1.4 import QtQuick.Layouts 1.4
import "../base" as Base import "../base" as Base
Rectangle { Base.HGlassRectangle {
id: banner id: banner
Layout.fillWidth: true Layout.fillWidth: true
Layout.preferredHeight: 32 Layout.preferredHeight: 32
color: "#BBB"
signal buttonClicked(string signalId) signal buttonClicked(string signalId)

View File

@ -1,21 +1,14 @@
import QtQuick 2.7 import QtQuick 2.7
import "../base" as Base import "../base" as Base
Base.HLabel { Base.HNoticeLabel {
property bool isToday: { text: dateTime.toLocaleDateString()
const today = new Date() color: Base.HStyle.chat.daybreak.foreground
return dateTime.getDate() == today.getDate() && backgroundColor: Base.HStyle.chat.daybreak.background
dateTime.getMonth() == today.getMonth() && radius: Base.HStyle.chat.daybreak.radius
dateTime.getFullYear() == today.getFullYear()
}
width: messageDelegate.width width: messageDelegate.width
topPadding: messageDelegate.isFirstMessage ? //topPadding: messageDelegate.isFirstMessage ?
0 : messageDelegate.standardSpacing //0 : messageDelegate.standardSpacing
bottomPadding: messageDelegate.standardSpacing //bottomPadding: messageDelegate.standardSpacing
text: dateTime.toLocaleDateString() + (isToday ? qsTr(" (Today)") : "")
horizontalAlignment: Text.AlignHCenter
font.pixelSize: Base.HStyle.fontSize.big
color: "darkolivegreen"
} }

View File

@ -23,16 +23,23 @@ RowLayout {
Base.HLabel { Base.HLabel {
id: contentLabel id: contentLabel
text: "<font color='" + text: "<font color='" +
(isUndecryptableEvent ? "darkred" : "gray") + "'>" + Qt.hsla(Backend.hueFromString(displayName.value || dict.sender),
(displayName.value || dict.sender) + Base.HStyle.chat.event.saturation,
(contentText.startsWith("'s ") ? "" : " ") + Base.HStyle.chat.event.lightness,
1) +
"'>" +
(displayName.value || dict.sender) + " " +
contentText + contentText +
"&nbsp;&nbsp;<font size=" + Base.HStyle.fontSize.small +
"px color='gray'>" + "&nbsp;&nbsp;" +
"<font size=" + Base.HStyle.fontSize.small + "px " +
"color=" + Base.HStyle.chat.event.date + ">" +
Qt.formatDateTime(dateTime, "hh:mm:ss") + Qt.formatDateTime(dateTime, "hh:mm:ss") +
"</font></font>" "</font> " +
"</font>"
textFormat: Text.RichText textFormat: Text.RichText
background: Rectangle {color: "#DDD"} background: Rectangle {color: Base.HStyle.chat.event.background}
wrapMode: Text.Wrap wrapMode: Text.Wrap
leftPadding: horizontalPadding leftPadding: horizontalPadding

View File

@ -6,6 +6,8 @@ import "../base" as Base
Banner { Banner {
property var inviter: null property var inviter: null
color: Base.HStyle.chat.inviteBanner.background
avatarName: inviter ? inviter.displayname : "" avatarName: inviter ? inviter.displayname : ""
//avatarSource: inviter ? inviter.avatar_url : "" //avatarSource: inviter ? inviter.avatar_url : ""

View File

@ -7,6 +7,8 @@ import "utils.js" as ChatJS
Banner { Banner {
property var leftEvent: null property var leftEvent: null
color: Base.HStyle.chat.leftBanner.background
onButtonClicked: if (signalId === "forget") { onButtonClicked: if (signalId === "forget") {
chatPage.canLoadPastEvents = false chatPage.canLoadPastEvents = false
pageStack.clear() pageStack.clear()

View File

@ -18,8 +18,11 @@ Row {
visible: ! combine visible: ! combine
id: nameLabel id: nameLabel
text: displayName.value || dict.sender text: displayName.value || dict.sender
background: Rectangle {color: "#DDD"} background: Rectangle {color: Base.HStyle.chat.message.background}
color: Qt.hsla(Backend.hueFromString(text), 0.22, 0.4, 1) color: Qt.hsla(Backend.hueFromString(text),
Base.HStyle.displayName.saturation,
Base.HStyle.displayName.lightness,
1)
elide: Text.ElideRight elide: Text.ElideRight
maximumLineCount: 1 maximumLineCount: 1
Layout.preferredWidth: contentLabel.width Layout.preferredWidth: contentLabel.width
@ -36,14 +39,15 @@ Row {
Backend.htmlFilter.filter(dict.formatted_body) : Backend.htmlFilter.filter(dict.formatted_body) :
dict.body) + dict.body) +
"&nbsp;&nbsp;<font size=" + Base.HStyle.fontSize.small + "&nbsp;&nbsp;<font size=" + Base.HStyle.fontSize.small +
"px color=gray>" + "px color=" + Base.HStyle.chat.message.date + ">" +
Qt.formatDateTime(dateTime, "hh:mm:ss") + Qt.formatDateTime(dateTime, "hh:mm:ss") +
"</font>" + "</font>" +
(isLocalEcho ? (isLocalEcho ?
"&nbsp;<font size=" + Base.HStyle.fontSize.small + "&nbsp;<font size=" + Base.HStyle.fontSize.small +
"px>⏳</font>" : "") "px>⏳</font>" : "")
textFormat: Text.RichText textFormat: Text.RichText
background: Rectangle {color: "#DDD"} background: Rectangle {color: Base.HStyle.chat.message.background}
color: Base.HStyle.chat.message.body
wrapMode: Text.Wrap wrapMode: Text.Wrap
leftPadding: horizontalPadding leftPadding: horizontalPadding

View File

@ -67,12 +67,19 @@ Column {
topPadding: topPadding:
isFirstEvent ? 0 : isFirstEvent ? 0 :
dayBreak ? standardSpacing * 2 :
talkBreak ? standardSpacing * 3 : talkBreak ? standardSpacing * 3 :
combine ? standardSpacing / 4 : combine ? standardSpacing / 4 :
standardSpacing standardSpacing
Daybreak { visible: dayBreak } Daybreak { visible: dayBreak }
Item {
visible: dayBreak
width: parent.width
height: topPadding
}
MessageContent { visible: isMessage } MessageContent { visible: isMessage }
EventContent { visible: ! isMessage } EventContent { visible: ! isMessage }

View File

@ -3,21 +3,24 @@ import QtQuick.Controls 2.2
import QtQuick.Layouts 1.4 import QtQuick.Layouts 1.4
import "../base" as Base import "../base" as Base
Rectangle { Base.HGlassRectangle {
property bool canLoadPastEvents: true property bool canLoadPastEvents: true
property int space: 8 property int space: 8
color: "transparent"
Layout.fillWidth: true Layout.fillWidth: true
Layout.fillHeight: true Layout.fillHeight: true
Layout.leftMargin: space
Layout.rightMargin: space
ListView { ListView {
id: messageListView id: messageListView
anchors.fill: parent
delegate: MessageDelegate {} delegate: MessageDelegate {}
model: Backend.models.roomEvents.get(chatPage.roomId) model: Backend.models.roomEvents.get(chatPage.roomId)
anchors.fill: parent
anchors.leftMargin: space
anchors.rightMargin: space
clip: true clip: true
topMargin: space topMargin: space
bottomMargin: space bottomMargin: space
@ -45,7 +48,7 @@ Rectangle {
topPadding: padding / 3 topPadding: padding / 3
bottomPadding: topPadding bottomPadding: topPadding
background: Rectangle { background: Rectangle {
color: "lightgray" color: Base.HStyle.chat.messageList.background
radius: 5 radius: 5
} }
} }

View File

@ -3,7 +3,7 @@ import QtQuick.Controls 2.2
import QtQuick.Layouts 1.4 import QtQuick.Layouts 1.4
import "../base" as Base import "../base" as Base
Rectangle { Base.HGlassRectangle {
property string displayName: "" property string displayName: ""
property string topic: "" property string topic: ""
@ -11,7 +11,7 @@ Rectangle {
Layout.fillWidth: true Layout.fillWidth: true
Layout.minimumHeight: 36 Layout.minimumHeight: 36
Layout.maximumHeight: Layout.minimumHeight Layout.maximumHeight: Layout.minimumHeight
color: "#BBB" color: Base.HStyle.chat.roomHeader.background
RowLayout { RowLayout {
id: row id: row

View File

@ -3,7 +3,7 @@ import QtQuick.Controls 2.2
import QtQuick.Layouts 1.4 import QtQuick.Layouts 1.4
import "../base" as Base import "../base" as Base
Rectangle { Base.HGlassRectangle {
function setFocus() { textArea.forceActiveFocus() } function setFocus() { textArea.forceActiveFocus() }
id: root id: root
@ -12,7 +12,7 @@ Rectangle {
Layout.preferredHeight: textArea.implicitHeight Layout.preferredHeight: textArea.implicitHeight
// parent.height / 2 causes binding loop? // parent.height / 2 causes binding loop?
Layout.maximumHeight: pageStack.height / 2 Layout.maximumHeight: pageStack.height / 2
color: "#BBB" color: Base.HStyle.chat.sendBox.background
RowLayout { RowLayout {
anchors.fill: parent anchors.fill: parent

View File

@ -3,21 +3,6 @@ import QtQuick.Controls 2.2
import QtQuick.Layouts 1.4 import QtQuick.Layouts 1.4
import "../base" as Base import "../base" as Base
Base.HRowLayout { Base.HNoticeLabel {
Base.HLabel { text: "Select or add a room to start."
text: "Select or add a room to start."
wrapMode: Text.Wrap
padding: 3
leftPadding: 10
rightPadding: 10
Layout.margins: 10
Layout.alignment: Qt.AlignCenter
Layout.maximumWidth: parent.width - Layout.margins * 2
background: Rectangle {
color: Base.HStyle.boxes.background
radius: Base.HStyle.boxes.radius
}
}
} }

View File

@ -11,5 +11,5 @@ Base.HLabel {
elide: Text.ElideRight elide: Text.ElideRight
maximumLineCount: 1 maximumLineCount: 1
font.bold: true font.weight: Font.DemiBold
} }

View File

@ -8,6 +8,8 @@ Base.HGlassRectangle {
id: sidePane id: sidePane
clip: true // Avoid artifacts when resizing pane width to minimum clip: true // Avoid artifacts when resizing pane width to minimum
isPageStackDescendant: false
ColumnLayout { ColumnLayout {
anchors.fill: parent anchors.fill: parent
spacing: 0 spacing: 0

View File

@ -19,21 +19,16 @@ function getLastRoomEventText(roomId, accountId) {
var undecryptable = ev.type === "OlmEvent" || ev.type === "MegolmEvent" var undecryptable = ev.type === "OlmEvent" || ev.type === "MegolmEvent"
if (undecryptable || ev.type.startsWith("RoomMessage")) { if (undecryptable || ev.type.startsWith("RoomMessage")) {
var color = ev.dict.sender === roomList.forUserId ? var color = Qt.hsla(Backend.hueFromString(name), 0.32, 0.3, 1)
"darkblue" : "purple"
return "<font color='" + return "<font color='" + color + "'>" +
color +
"'>" +
name + name +
":</font> " + ":</font> " +
(undecryptable ? (undecryptable ?
"<font color='darkred'>Undecryptable<font>" : "<font color='darkred'>" + qsTr("Undecryptable") + "<font>" :
ev.dict.body) ev.dict.body)
} else { } else {
return "<font color='" + return "<font color='" + (undecryptable ? "darkred" : "#444") + "'>" +
(undecryptable ? "darkred" : "#444") +
"'>" +
name + name +
" " + " " +
ChatJS.getEventText(ev.type, ev.dict) + ChatJS.getEventText(ev.type, ev.dict) +