Better message bubbles.
This commit is contained in:
parent
927a0aa017
commit
50445bccf1
|
@ -15,7 +15,7 @@ import Spectral.Font 0.1
|
|||
import Spectral.Effect 2.0
|
||||
|
||||
ColumnLayout {
|
||||
readonly property bool avatarVisible: !sentByMe && (aboveAuthor !== author || aboveSection !== section || aboveEventType === "state" || aboveEventType === "emote" || aboveEventType === "other")
|
||||
readonly property bool avatarVisible: !sentByMe && showAuthor
|
||||
readonly property bool sentByMe: author === currentRoom.localUser
|
||||
|
||||
property bool openOnFinished: false
|
||||
|
@ -39,8 +39,6 @@ ColumnLayout {
|
|||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.alignment: sentByMe ? Qt.AlignRight : Qt.AlignLeft
|
||||
|
||||
z: -5
|
||||
|
||||
id: messageRow
|
||||
|
@ -111,7 +109,7 @@ ColumnLayout {
|
|||
}
|
||||
|
||||
Label {
|
||||
text: progressInfo.active ? (progressInfo.progress + "/" + progressInfo.total) : content.info ? content.info.size : "Unknown"
|
||||
text: progressInfo.active ? (humanSize(progressInfo.progress) + "/" + humanSize(progressInfo.total)) : humanSize(content.info ? content.info.size : 0)
|
||||
color: MPalette.lighter
|
||||
}
|
||||
}
|
||||
|
@ -195,4 +193,20 @@ ColumnLayout {
|
|||
if (Qt.openUrlExternally(progressInfo.localPath)) return;
|
||||
if (Qt.openUrlExternally(progressInfo.localDir)) return;
|
||||
}
|
||||
|
||||
|
||||
function humanSize(bytes)
|
||||
{
|
||||
if (!bytes)
|
||||
return qsTr("Unknown", "Unknown attachment size")
|
||||
if (bytes < 4000)
|
||||
return qsTr("%1 bytes").arg(bytes)
|
||||
bytes = Math.round(bytes / 100) / 10
|
||||
if (bytes < 2000)
|
||||
return qsTr("%1 KB").arg(bytes)
|
||||
bytes = Math.round(bytes / 100) / 10
|
||||
if (bytes < 2000)
|
||||
return qsTr("%1 MB").arg(bytes)
|
||||
return qsTr("%1 GB").arg(Math.round(bytes / 100) / 10)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ import Spectral.Effect 2.0
|
|||
import Spectral.Font 0.1
|
||||
|
||||
ColumnLayout {
|
||||
readonly property bool avatarVisible: !sentByMe && (aboveAuthor !== author || aboveSection !== section || aboveEventType === "state" || aboveEventType === "emote" || aboveEventType === "other")
|
||||
readonly property bool avatarVisible: !sentByMe && showAuthor
|
||||
readonly property bool sentByMe: author === currentRoom.localUser
|
||||
|
||||
property bool openOnFinished: false
|
||||
|
@ -44,8 +44,6 @@ ColumnLayout {
|
|||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.alignment: sentByMe ? Qt.AlignRight : Qt.AlignLeft
|
||||
|
||||
z: -5
|
||||
|
||||
id: messageRow
|
||||
|
@ -121,17 +119,6 @@ ColumnLayout {
|
|||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
|
||||
color: "transparent"
|
||||
radius: 24
|
||||
antialiasing: true
|
||||
|
||||
border.width: 4
|
||||
border.color: MPalette.background
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ import Spectral.Menu.Timeline 2.0
|
|||
import Spectral.Effect 2.0
|
||||
|
||||
RowLayout {
|
||||
readonly property bool avatarVisible: !sentByMe && (aboveAuthor !== author || aboveSection !== section || aboveEventType === "state" || aboveEventType === "emote" || aboveEventType === "other")
|
||||
readonly property bool avatarVisible: !sentByMe && showAuthor
|
||||
readonly property bool sentByMe: author === currentRoom.localUser
|
||||
readonly property bool darkBackground: !sentByMe
|
||||
readonly property bool replyVisible: replyEventId || false
|
||||
|
@ -68,6 +68,58 @@ RowLayout {
|
|||
radius: 18
|
||||
antialiasing: true
|
||||
|
||||
Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
|
||||
width: parent.width / 2
|
||||
height: parent.height / 2
|
||||
|
||||
visible: !sentByMe && (bubbleShape == 3 || bubbleShape == 2)
|
||||
|
||||
color: sentByMe ? MPalette.background : eventType === "notice" ? MPalette.primary : MPalette.accent
|
||||
radius: 2
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
|
||||
width: parent.width / 2
|
||||
height: parent.height / 2
|
||||
|
||||
visible: sentByMe && (bubbleShape == 3 || bubbleShape == 2)
|
||||
|
||||
color: sentByMe ? MPalette.background : eventType === "notice" ? MPalette.primary : MPalette.accent
|
||||
radius: 2
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
|
||||
width: parent.width / 2
|
||||
height: parent.height / 2
|
||||
|
||||
visible: !sentByMe && (bubbleShape == 1 || bubbleShape == 2)
|
||||
|
||||
color: sentByMe ? MPalette.background : eventType === "notice" ? MPalette.primary : MPalette.accent
|
||||
radius: 2
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
|
||||
width: parent.width / 2
|
||||
height: parent.height / 2
|
||||
|
||||
visible: sentByMe && (bubbleShape == 1 || bubbleShape == 2)
|
||||
|
||||
color: sentByMe ? MPalette.background : eventType === "notice" ? MPalette.primary : MPalette.accent
|
||||
radius: 2
|
||||
}
|
||||
|
||||
AutoMouseArea {
|
||||
anchors.fill: parent
|
||||
|
||||
|
|
|
@ -105,7 +105,7 @@ Item {
|
|||
|
||||
id: messageListView
|
||||
|
||||
spacing: 4
|
||||
spacing: 2
|
||||
|
||||
displayMarginBeginning: 100
|
||||
displayMarginEnd: 100
|
||||
|
@ -186,6 +186,8 @@ Item {
|
|||
DelegateChoice {
|
||||
roleValue: "image"
|
||||
delegate: ImageDelegate {
|
||||
anchors.right: sentByMe ? parent.right : undefined
|
||||
|
||||
Layout.maximumWidth: parent.width
|
||||
}
|
||||
}
|
||||
|
@ -193,6 +195,8 @@ Item {
|
|||
DelegateChoice {
|
||||
roleValue: "file"
|
||||
delegate: FileDelegate {
|
||||
anchors.right: sentByMe ? parent.right : undefined
|
||||
|
||||
Layout.maximumWidth: parent.width
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,14 +18,10 @@ QHash<int, QByteArray> MessageEventModel::roleNames() const {
|
|||
QHash<int, QByteArray> roles = QAbstractItemModel::roleNames();
|
||||
roles[EventTypeRole] = "eventType";
|
||||
roles[MessageRole] = "message";
|
||||
roles[AboveEventTypeRole] = "aboveEventType";
|
||||
roles[EventIdRole] = "eventId";
|
||||
roles[TimeRole] = "time";
|
||||
roles[AboveTimeRole] = "aboveTime";
|
||||
roles[SectionRole] = "section";
|
||||
roles[AboveSectionRole] = "aboveSection";
|
||||
roles[AuthorRole] = "author";
|
||||
roles[AboveAuthorRole] = "aboveAuthor";
|
||||
roles[ContentRole] = "content";
|
||||
roles[ContentTypeRole] = "contentType";
|
||||
roles[HighlightRole] = "highlight";
|
||||
|
@ -38,6 +34,9 @@ QHash<int, QByteArray> MessageEventModel::roleNames() const {
|
|||
roles[ReplyAuthorRole] = "replyAuthor";
|
||||
roles[ReplyDisplayRole] = "replyDisplay";
|
||||
roles[UserMarkerRole] = "userMarker";
|
||||
roles[ShowTimestampRole] = "showTimestamp";
|
||||
roles[ShowAuthorRole] = "showAuthor";
|
||||
roles[BubbleShapeRole] = "bubbleShape";
|
||||
return roles;
|
||||
}
|
||||
|
||||
|
@ -84,9 +83,9 @@ void MessageEventModel::setRoom(SpectralRoom* room) {
|
|||
if (biggest < m_currentRoom->maxTimelineIndex()) {
|
||||
auto rowBelowInserted = m_currentRoom->maxTimelineIndex() -
|
||||
biggest + timelineBaseIndex() - 1;
|
||||
refreshEventRoles(rowBelowInserted,
|
||||
{AboveEventTypeRole, AboveAuthorRole,
|
||||
AboveSectionRole, AboveTimeRole});
|
||||
refreshEventRoles(
|
||||
rowBelowInserted,
|
||||
{ShowTimestampRole, ShowAuthorRole, BubbleShapeRole});
|
||||
}
|
||||
for (auto i = m_currentRoom->maxTimelineIndex() - biggest;
|
||||
i <= m_currentRoom->maxTimelineIndex() - lowest; ++i)
|
||||
|
@ -117,8 +116,7 @@ void MessageEventModel::setRoom(SpectralRoom* room) {
|
|||
refreshEventRoles(timelineBaseIndex() + 1, {ReadMarkerRole});
|
||||
if (timelineBaseIndex() > 0) // Refresh below, see #312
|
||||
refreshEventRoles(timelineBaseIndex() - 1,
|
||||
{AboveEventTypeRole, AboveAuthorRole,
|
||||
AboveSectionRole, AboveTimeRole});
|
||||
{ShowTimestampRole, ShowAuthorRole, BubbleShapeRole});
|
||||
});
|
||||
connect(m_currentRoom, &Room::pendingEventChanged, this,
|
||||
&MessageEventModel::refreshRow);
|
||||
|
@ -417,22 +415,49 @@ QVariant MessageEventModel::data(const QModelIndex& idx, int role) const {
|
|||
return {};
|
||||
}
|
||||
|
||||
if (role == AboveEventTypeRole || role == AboveSectionRole ||
|
||||
role == AboveAuthorRole || role == AboveTimeRole)
|
||||
if (role == ShowTimestampRole || role == ShowAuthorRole)
|
||||
for (auto r = row + 1; r < rowCount(); ++r) {
|
||||
auto i = index(r);
|
||||
if (data(i, SpecialMarksRole) != EventStatus::Hidden)
|
||||
if (data(i, SpecialMarksRole) != EventStatus::Hidden) {
|
||||
switch (role) {
|
||||
case AboveEventTypeRole:
|
||||
return data(i, EventTypeRole);
|
||||
case AboveSectionRole:
|
||||
return data(i, SectionRole);
|
||||
case AboveAuthorRole:
|
||||
return data(i, AuthorRole);
|
||||
case AboveTimeRole:
|
||||
return data(i, TimeRole);
|
||||
case ShowTimestampRole:
|
||||
return data(i, TimeRole)
|
||||
.toDateTime()
|
||||
.msecsTo(data(idx, TimeRole).toDateTime()) > 600000;
|
||||
case ShowAuthorRole:
|
||||
return data(i, AuthorRole) != data(idx, AuthorRole);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (role == BubbleShapeRole) { // TODO: Convoluted logic.
|
||||
int belowRow = -1; // Invalid
|
||||
|
||||
for (auto r = row - 1; r >= 0; --r) {
|
||||
auto i = index(r);
|
||||
if (data(i, SpecialMarksRole) != EventStatus::Hidden) {
|
||||
belowRow = r;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool aboveShow, belowShow;
|
||||
aboveShow = data(idx, ShowAuthorRole).toBool() ||
|
||||
data(idx, ShowTimestampRole).toBool();
|
||||
if (belowRow == -1)
|
||||
belowShow = true;
|
||||
else
|
||||
belowShow = data(index(belowRow), ShowAuthorRole).toBool() ||
|
||||
data(index(belowRow), ShowTimestampRole).toBool();
|
||||
|
||||
if (aboveShow && belowShow)
|
||||
return BubbleShapes::NoShape;
|
||||
if (aboveShow && !belowShow)
|
||||
return BubbleShapes::BeginShape;
|
||||
if (belowShow)
|
||||
return BubbleShapes::EndShape;
|
||||
return BubbleShapes::MiddleShape;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
|
|
@ -14,14 +14,10 @@ class MessageEventModel : public QAbstractListModel {
|
|||
enum EventRoles {
|
||||
EventTypeRole = Qt::UserRole + 1,
|
||||
MessageRole,
|
||||
AboveEventTypeRole,
|
||||
EventIdRole,
|
||||
TimeRole,
|
||||
AboveTimeRole,
|
||||
SectionRole,
|
||||
AboveSectionRole,
|
||||
AuthorRole,
|
||||
AboveAuthorRole,
|
||||
ContentRole,
|
||||
ContentTypeRole,
|
||||
HighlightRole,
|
||||
|
@ -30,13 +26,25 @@ class MessageEventModel : public QAbstractListModel {
|
|||
LongOperationRole,
|
||||
AnnotationRole,
|
||||
UserMarkerRole,
|
||||
// For reply
|
||||
ReplyEventIdRole,
|
||||
ReplyAuthorRole,
|
||||
ReplyDisplayRole,
|
||||
|
||||
ShowTimestampRole,
|
||||
ShowAuthorRole,
|
||||
BubbleShapeRole,
|
||||
// For debugging
|
||||
EventResolvedTypeRole,
|
||||
};
|
||||
|
||||
enum BubbleShapes {
|
||||
NoShape = 0,
|
||||
BeginShape,
|
||||
MiddleShape,
|
||||
EndShape,
|
||||
};
|
||||
|
||||
explicit MessageEventModel(QObject* parent = nullptr);
|
||||
~MessageEventModel();
|
||||
|
||||
|
|
Loading…
Reference in New Issue