diff --git a/imports/Spectral/Component/Avatar.qml b/imports/Spectral/Component/Avatar.qml
index 399f465..fe546eb 100644
--- a/imports/Spectral/Component/Avatar.qml
+++ b/imports/Spectral/Component/Avatar.qml
@@ -36,8 +36,8 @@ Item {
visible: !realSource || image.status != Image.Ready
radius: height / 2
-
color: stringToColor(hint)
+ antialiasing: true
Label {
anchors.centerIn: parent
diff --git a/imports/Spectral/Component/FullScreenImage.qml b/imports/Spectral/Component/FullScreenImage.qml
new file mode 100644
index 0000000..694ac86
--- /dev/null
+++ b/imports/Spectral/Component/FullScreenImage.qml
@@ -0,0 +1,41 @@
+import QtQuick 2.12
+import QtQuick.Controls 2.12
+
+ApplicationWindow {
+ property url imageUrl
+ property int sourceWidth
+ property int sourceHeight
+
+ id: root
+
+ flags: Qt.FramelessWindowHint | Qt.WA_TranslucentBackground
+ visible: true
+ visibility: Qt.WindowFullScreen
+
+ title: "Image View - " + imageUrl
+
+ color: "#BB000000"
+
+ Image {
+ anchors.centerIn: parent
+
+ sourceSize.width: root.sourceWidth
+ sourceSize.height: root.sourceHeight
+ source: imageUrl
+ }
+
+ ItemDelegate {
+ anchors.top: parent.top
+ anchors.right: parent.right
+
+ width: 64
+ height: 64
+
+ contentItem: MaterialIcon {
+ icon: "\ue5cd"
+ color: "white"
+ }
+
+ onClicked: root.close()
+ }
+}
diff --git a/imports/Spectral/Component/Timeline/ImageDelegate.qml b/imports/Spectral/Component/Timeline/ImageDelegate.qml
index 9bb170f..b92881c 100644
--- a/imports/Spectral/Component/Timeline/ImageDelegate.qml
+++ b/imports/Spectral/Component/Timeline/ImageDelegate.qml
@@ -83,10 +83,13 @@ ColumnLayout {
id: img
source: "image://mxc/" +
- (content.info && content.info.thumbnail_info ?
- content.thumbnailMediaId : content.mediaId)
- sourceSize.width: messageListView.width * 0.6
- sourceSize.height: messageListView.height
+ (content.info && content.info.thumbnail_info ?
+ content.thumbnailMediaId : content.mediaId)
+
+ sourceSize.width: 720
+ sourceSize.height: 720
+
+ fillMode: Image.PreserveAspectCrop
layer.enabled: true
layer.effect: OpacityMask {
@@ -97,6 +100,16 @@ ColumnLayout {
}
}
+ Component {
+ id: fullScreenImage
+
+ FullScreenImage {
+ imageUrl: "image://mxc/" + content.mediaId
+ sourceWidth: content.info.w
+ sourceHeight: content.info.h
+ }
+ }
+
Rectangle {
anchors.fill: parent
@@ -113,6 +126,11 @@ ColumnLayout {
id: messageMouseArea
+ onPrimaryClicked: {
+ var window = fullScreenImage.createObject()
+ window.show()
+ }
+
onSecondaryClicked: messageContextMenu.popup()
Menu {
@@ -126,16 +144,19 @@ ColumnLayout {
sourceDialog.open()
}
}
+
MenuItem {
text: "Open Externally"
onTriggered: downloadAndOpen()
}
+
MenuItem {
text: "Save As"
onTriggered: saveFileAs()
}
+
MenuItem {
text: "Reply"
@@ -147,6 +168,7 @@ ColumnLayout {
roomPanelInput.focus()
}
}
+
MenuItem {
text: "Redact"
diff --git a/imports/Spectral/Component/qmldir b/imports/Spectral/Component/qmldir
index be035c4..d929c81 100644
--- a/imports/Spectral/Component/qmldir
+++ b/imports/Spectral/Component/qmldir
@@ -7,3 +7,4 @@ AutoListView 2.0 AutoListView.qml
AutoTextField 2.0 AutoTextField.qml
SplitView 2.0 SplitView.qml
Avatar 2.0 Avatar.qml
+FullScreenImage 2.0 FullScreenImage.qml
diff --git a/imports/Spectral/Panel/RoomDrawer.qml b/imports/Spectral/Panel/RoomDrawer.qml
index 6817a91..72a1e8d 100644
--- a/imports/Spectral/Panel/RoomDrawer.qml
+++ b/imports/Spectral/Panel/RoomDrawer.qml
@@ -271,6 +271,102 @@ Drawer {
}
}
+ Control {
+ Layout.fillWidth: true
+
+ visible: room ? room.predecessorId : false
+
+ padding: 8
+
+ contentItem: RowLayout {
+ MaterialIcon {
+ Layout.preferredWidth: 48
+ Layout.preferredHeight: 48
+
+ icon: "\ue8d4"
+ }
+
+ ColumnLayout {
+ Layout.fillWidth: true
+
+ spacing: 0
+
+ Label {
+ Layout.fillWidth: true
+
+ font.bold: true
+ color: MPalette.foreground
+ text: "This room is a continuation of another conversation."
+ }
+
+ Label {
+ Layout.fillWidth: true
+
+ color: MPalette.lighter
+ text: "Click here to see older messages."
+ }
+ }
+ }
+
+ background: Rectangle {
+ color: MPalette.banner
+
+ RippleEffect {
+ anchors.fill: parent
+
+ onClicked: roomListForm.enteredRoom = spectralController.connection.room(room.predecessorId)
+ }
+ }
+ }
+
+ Control {
+ Layout.fillWidth: true
+
+ visible: room ? room.successorId : false
+
+ padding: 8
+
+ contentItem: RowLayout {
+ MaterialIcon {
+ Layout.preferredWidth: 48
+ Layout.preferredHeight: 48
+
+ icon: "\ue8d4"
+ }
+
+ ColumnLayout {
+ Layout.fillWidth: true
+
+ spacing: 0
+
+ Label {
+ Layout.fillWidth: true
+
+ font.bold: true
+ color: MPalette.foreground
+ text: "This room has been replaced and is no longer active."
+ }
+
+ Label {
+ Layout.fillWidth: true
+
+ color: MPalette.lighter
+ text: "The conversation continues here."
+ }
+ }
+ }
+
+ background: Rectangle {
+ color: MPalette.banner
+
+ RippleEffect {
+ anchors.fill: parent
+
+ onClicked: roomListForm.enteredRoom = spectralController.connection.room(room.successorId)
+ }
+ }
+ }
+
MenuSeparator {
Layout.fillWidth: true
}
diff --git a/imports/Spectral/Panel/RoomListPanel.qml b/imports/Spectral/Panel/RoomListPanel.qml
index e2d0700..b6f701f 100644
--- a/imports/Spectral/Panel/RoomListPanel.qml
+++ b/imports/Spectral/Panel/RoomListPanel.qml
@@ -60,6 +60,9 @@ Item {
]
filters: [
+ ExpressionFilter {
+ expression: joinState != "upgraded"
+ },
RegExpFilter {
roleName: "name"
pattern: searchField.text
@@ -272,7 +275,7 @@ Item {
}
Rectangle {
- width: unreadCount > 0 ? 4 : 0
+ width: unreadCount >= 0 ? 4 : 0
height: parent.height
color: Material.accent
diff --git a/res.qrc b/res.qrc
index d5d29dd..63748cb 100644
--- a/res.qrc
+++ b/res.qrc
@@ -43,5 +43,6 @@
imports/Spectral/Component/Avatar.qml
imports/Spectral/Setting/Palette.qml
imports/Spectral/Component/Timeline/FileDelegate.qml
+ imports/Spectral/Component/FullScreenImage.qml
diff --git a/src/roomlistmodel.cpp b/src/roomlistmodel.cpp
index 2c574de..425aefd 100644
--- a/src/roomlistmodel.cpp
+++ b/src/roomlistmodel.cpp
@@ -195,6 +195,11 @@ QVariant RoomListModel::data(const QModelIndex& index, int role) const {
return room->lastEvent();
if (role == LastActiveTimeRole)
return room->lastActiveTime();
+ if (role == JoinStateRole) {
+ if (!room->successorId().isEmpty())
+ return QStringLiteral("upgraded");
+ return toCString(room->joinState());
+ }
if (role == CurrentRoomRole)
return QVariant::fromValue(room);
return QVariant();
@@ -231,6 +236,7 @@ QHash RoomListModel::roleNames() const {
roles[HighlightCountRole] = "highlightCount";
roles[LastEventRole] = "lastEvent";
roles[LastActiveTimeRole] = "lastActiveTime";
+ roles[JoinStateRole] = "joinState";
roles[CurrentRoomRole] = "currentRoom";
return roles;
}
diff --git a/src/roomlistmodel.h b/src/roomlistmodel.h
index 23ea92b..238b372 100644
--- a/src/roomlistmodel.h
+++ b/src/roomlistmodel.h
@@ -39,6 +39,7 @@ class RoomListModel : public QAbstractListModel {
HighlightCountRole,
LastEventRole,
LastActiveTimeRole,
+ JoinStateRole,
CurrentRoomRole,
};