diff --git a/resources/qml/ChatPage.qml b/resources/qml/ChatPage.qml index e5b53738..0f884d75 100644 --- a/resources/qml/ChatPage.qml +++ b/resources/qml/ChatPage.qml @@ -14,8 +14,11 @@ Rectangle { color: Nheko.colors.window AdaptiveLayout { + id: adaptiveView + anchors.fill: parent singlePageMode: width < communityListC.maximumWidth + roomListC.maximumWidth + timlineViewC.minimumWidth + pageIndex: Rooms.currentRoom ? 2 : 1 AdaptiveLayoutElement { id: communityListC @@ -37,9 +40,12 @@ Rectangle { minimumWidth: Nheko.avatarSize * 5 + Nheko.paddingSmall * 2 preferredWidth: Nheko.avatarSize * 5 + Nheko.paddingSmall * 2 maximumWidth: Nheko.avatarSize * 10 + Nheko.paddingSmall * 2 - collapsedWidth: Nheko.avatarSize + Nheko.paddingSmall * 2 + collapsedWidth: roomlist.avatarSize + 2 * Nheko.paddingMedium RoomList { + id: roomlist + + collapsed: parent.collapsed } } @@ -52,6 +58,7 @@ Rectangle { TimelineView { id: timeline + showBackButton: adaptiveView.singlePageMode room: Rooms.currentRoom } diff --git a/resources/qml/RoomList.qml b/resources/qml/RoomList.qml index ce991dec..21973b77 100644 --- a/resources/qml/RoomList.qml +++ b/resources/qml/RoomList.qml @@ -13,6 +13,8 @@ import im.nheko 1.0 Page { //leftPadding: Nheko.paddingSmall //rightPadding: Nheko.paddingSmall + property int avatarSize: Math.ceil(fontMetrics.lineSpacing * 2.3) + property bool collapsed: false ListView { id: roomlist @@ -113,9 +115,11 @@ Page { property color bubbleText: Nheko.colors.highlightedText color: background - height: Math.ceil(fontMetrics.lineSpacing * 2.3 + Nheko.paddingMedium * 2) + height: avatarSize + 2 * Nheko.paddingMedium width: ListView.view.width state: "normal" + ToolTip.visible: hovered.hovered && collapsed + ToolTip.text: model.roomName states: [ State { name: "highlight" @@ -148,7 +152,7 @@ Page { ] TapHandler { - margin: -2 + margin: -Nheko.paddingSmall acceptedButtons: Qt.RightButton onSingleTapped: { if (!TimelineManager.isInvite) @@ -159,7 +163,7 @@ Page { } TapHandler { - margin: -2 + margin: -Nheko.paddingSmall onSingleTapped: Rooms.setCurrentRoom(model.roomId) onLongPressed: { if (!TimelineManager.isInvite) @@ -169,8 +173,9 @@ Page { } HoverHandler { - margin: -2 id: hovered + + margin: -Nheko.paddingSmall } RowLayout { @@ -186,15 +191,46 @@ Page { enabled: false Layout.alignment: Qt.AlignVCenter - height: Math.ceil(fontMetrics.lineSpacing * 2.3) - width: Math.ceil(fontMetrics.lineSpacing * 2.3) + height: avatarSize + width: avatarSize url: model.avatarUrl.replace("mxc://", "image://MxcImage/") displayName: model.roomName + + Rectangle { + id: collapsedNotificationBubble + + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.margins: -Nheko.paddingSmall + visible: collapsed && model.notificationCount > 0 + enabled: false + Layout.alignment: Qt.AlignRight + height: fontMetrics.averageCharacterWidth * 3 + width: height + radius: height / 2 + color: model.hasLoudNotification ? Nheko.theme.red : roomItem.bubbleBackground + + Label { + anchors.centerIn: parent + width: parent.width * 0.8 + height: parent.height * 0.8 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + fontSizeMode: Text.Fit + font.bold: true + font.pixelSize: fontMetrics.font.pixelSize * 0.8 + color: model.hasLoudNotification ? "white" : roomItem.bubbleText + text: model.notificationCount > 99 ? "99+" : model.notificationCount + } + + } + } ColumnLayout { id: textContent + visible: !collapsed Layout.alignment: Qt.AlignLeft Layout.fillWidth: true Layout.minimumWidth: 100 @@ -396,7 +432,7 @@ Page { } TapHandler { - margin: -2 + margin: -Nheko.paddingSmall acceptedButtons: Qt.LeftButton onSingleTapped: userInfoPanel.openUserProfile() onLongPressed: userInfoMenu.open() @@ -404,7 +440,7 @@ Page { } TapHandler { - margin: -2 + margin: -Nheko.paddingSmall acceptedButtons: Qt.RightButton onSingleTapped: userInfoMenu.open() gesturePolicy: TapHandler.ReleaseWithinBounds @@ -431,6 +467,7 @@ Page { ColumnLayout { id: col + visible: !collapsed Layout.alignment: Qt.AlignLeft Layout.fillWidth: true width: parent.width - avatar.width - logoutButton.width - Nheko.paddingMedium * 2 @@ -462,6 +499,7 @@ Page { ImageButton { id: logoutButton + visible: !collapsed Layout.alignment: Qt.AlignVCenter image: ":/icons/icons/ui/power-button-off.png" ToolTip.visible: hovered @@ -533,6 +571,7 @@ Page { } ImageButton { + visible: !collapsed Layout.alignment: Qt.AlignBottom | Qt.AlignHCenter hoverEnabled: true width: 22 @@ -544,6 +583,7 @@ Page { } ImageButton { + visible: !collapsed Layout.alignment: Qt.AlignBottom | Qt.AlignRight hoverEnabled: true width: 22 diff --git a/resources/qml/TimelineView.qml b/resources/qml/TimelineView.qml index 747be61e..095103fa 100644 --- a/resources/qml/TimelineView.qml +++ b/resources/qml/TimelineView.qml @@ -19,6 +19,7 @@ Item { id: timelineView property var room: null + property bool showBackButton: false Label { visible: !room && !TimelineManager.isInitialSync @@ -45,6 +46,7 @@ Item { spacing: 0 TopBar { + showBackButton: timelineView.showBackButton } Rectangle { diff --git a/resources/qml/TopBar.qml b/resources/qml/TopBar.qml index 65e27939..30ab2e7c 100644 --- a/resources/qml/TopBar.qml +++ b/resources/qml/TopBar.qml @@ -11,6 +11,8 @@ import im.nheko 1.0 Rectangle { id: topBar + property bool showBackButton: false + Layout.fillWidth: true implicitHeight: topLayout.height + Nheko.paddingMedium * 2 z: 3 @@ -43,11 +45,11 @@ Rectangle { Layout.alignment: Qt.AlignVCenter width: Nheko.avatarSize height: Nheko.avatarSize - visible: TimelineManager.isNarrowView + visible: showBackButton image: ":/icons/icons/ui/angle-pointing-to-left.png" ToolTip.visible: hovered ToolTip.text: qsTr("Back to room list") - onClicked: TimelineManager.backToRooms() + onClicked: Rooms.resetCurrentRoom() } Avatar { diff --git a/resources/qml/components/AdaptiveLayout.qml b/resources/qml/components/AdaptiveLayout.qml index e6416414..eea85e38 100644 --- a/resources/qml/components/AdaptiveLayout.qml +++ b/resources/qml/components/AdaptiveLayout.qml @@ -18,6 +18,43 @@ Container { property int splitterGrabMargin: Nheko.paddingSmall property int pageIndex: 0 property Component handle + property Component handleToucharea + + anchors.fill: parent + Component.onCompleted: { + for (var i = 0; i < count - 1; i++) { + let handle_ = handle.createObject(contentChildren[i]); + let split_ = handleToucharea.createObject(contentChildren[i]); + contentChildren[i].width = Qt.binding(function() { + return split_.calculatedWidth; + }); + contentChildren[i].splitterWidth = Qt.binding(function() { + return handle_.width; + }); + } + contentChildren[count - 1].width = Qt.binding(function() { + if (container.singlePageMode) { + return container.width; + } else { + var w = container.width; + for (var i = 0; i < count - 1; i++) { + if (contentChildren[i].width) + w = w - contentChildren[i].width; + + } + return w; + } + }); + contentChildren[count - 1].splitterWidth = 0; + for (var i = 0; i < count; i++) { + contentChildren[i].height = Qt.binding(function() { + return container.height; + }); + contentChildren[i].children[0].height = Qt.binding(function() { + return container.height; + }); + } + } handle: Rectangle { z: 3 @@ -27,8 +64,6 @@ Container { anchors.right: parent.right } - property Component handleToucharea - handleToucharea: Item { id: splitter @@ -79,42 +114,6 @@ Container { } - anchors.fill: parent - Component.onCompleted: { - for (var i = 0; i < count - 1; i++) { - let handle_ = handle.createObject(contentChildren[i]); - let split_ = handleToucharea.createObject(contentChildren[i]); - contentChildren[i].width = Qt.binding(function() { - return split_.calculatedWidth; - }); - contentChildren[i].splitterWidth = Qt.binding(function() { - return handle_.width; - }); - } - contentChildren[count - 1].width = Qt.binding(function() { - if (container.singlePageMode) { - return container.width; - } else { - var w = container.width; - for (var i = 0; i < count - 1; i++) { - if (contentChildren[i].width) - w = w - contentChildren[i].width; - - } - return w; - } - }); - contentChildren[count - 1].splitterWidth = 0; - for (var i = 0; i < count; i++) { - contentChildren[i].height = Qt.binding(function() { - return container.height; - }); - contentChildren[i].children[0].height = Qt.binding(function() { - return container.height; - }); - } - } - contentItem: ListView { id: view diff --git a/src/timeline/RoomlistModel.h b/src/timeline/RoomlistModel.h index d3e1e1f9..fa991f6b 100644 --- a/src/timeline/RoomlistModel.h +++ b/src/timeline/RoomlistModel.h @@ -21,7 +21,8 @@ class TimelineViewManager; class RoomlistModel : public QAbstractListModel { Q_OBJECT - Q_PROPERTY(TimelineModel *currentRoom READ currentRoom NOTIFY currentRoomChanged) + Q_PROPERTY(TimelineModel *currentRoom READ currentRoom NOTIFY currentRoomChanged RESET + resetCurrentRoom) public: enum Roles { @@ -73,6 +74,11 @@ public slots: void leave(QString roomid); TimelineModel *currentRoom() const { return currentRoom_.get(); } void setCurrentRoom(QString roomid); + void resetCurrentRoom() + { + currentRoom_ = nullptr; + emit currentRoomChanged(); + } private slots: void updateReadStatus(const std::map roomReadStatus_); @@ -98,7 +104,8 @@ private: class FilteredRoomlistModel : public QSortFilterProxyModel { Q_OBJECT - Q_PROPERTY(TimelineModel *currentRoom READ currentRoom NOTIFY currentRoomChanged) + Q_PROPERTY(TimelineModel *currentRoom READ currentRoom NOTIFY currentRoomChanged RESET + resetCurrentRoom) public: FilteredRoomlistModel(RoomlistModel *model, QObject *parent = nullptr); bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; @@ -117,6 +124,7 @@ public slots: TimelineModel *currentRoom() const { return roomlistmodel->currentRoom(); } void setCurrentRoom(QString roomid) { roomlistmodel->setCurrentRoom(std::move(roomid)); } + void resetCurrentRoom() { roomlistmodel->resetCurrentRoom(); } void nextRoom(); void previousRoom(); diff --git a/src/timeline/TimelineModel.cpp b/src/timeline/TimelineModel.cpp index cd3febd5..f29f929e 100644 --- a/src/timeline/TimelineModel.cpp +++ b/src/timeline/TimelineModel.cpp @@ -891,7 +891,6 @@ TimelineModel::updateLastMessage() time}; if (description != lastMessage_) { lastMessage_ = description; - emit manager_->updateRoomsLastMessage(room_id_, lastMessage_); emit lastMessageChanged(); } return; @@ -906,7 +905,6 @@ TimelineModel::updateLastMessage() QString::fromStdString(mtx::accessors::sender(*event)))); if (description != lastMessage_) { lastMessage_ = description; - emit manager_->updateRoomsLastMessage(room_id_, description); emit lastMessageChanged(); } return; diff --git a/src/timeline/TimelineViewManager.h b/src/timeline/TimelineViewManager.h index c4707208..68d9cd1b 100644 --- a/src/timeline/TimelineViewManager.h +++ b/src/timeline/TimelineViewManager.h @@ -37,8 +37,6 @@ class TimelineViewManager : public QObject Q_PROPERTY( bool isInitialSync MEMBER isInitialSync_ READ isInitialSync NOTIFY initialSyncChanged) - Q_PROPERTY( - bool isNarrowView MEMBER isNarrowView_ READ isNarrowView NOTIFY narrowViewChanged) Q_PROPERTY( bool isWindowFocused MEMBER isWindowFocused_ READ isWindowFocused NOTIFY focusChanged) @@ -54,7 +52,6 @@ public: void clearAll() { rooms_->clear(); } Q_INVOKABLE bool isInitialSync() const { return isInitialSync_; } - bool isNarrowView() const { return isNarrowView_; } bool isWindowFocused() const { return isWindowFocused_; } Q_INVOKABLE void openImageOverlay(QString mxcUrl, QString eventId); Q_INVOKABLE QColor userColor(QString id, QColor background); @@ -74,16 +71,12 @@ public: void verifyDevice(QString userid, QString deviceid); signals: - void clearRoomMessageCount(QString roomid); - void updateRoomsLastMessage(QString roomid, const DescInfo &info); void activeTimelineChanged(TimelineModel *timeline); void initialSyncChanged(bool isInitialSync); void replyingEventChanged(QString replyingEvent); void replyClosed(); void newDeviceVerificationRequest(DeviceVerificationFlow *flow); void inviteUsers(QStringList users); - void showRoomList(); - void narrowViewChanged(); void focusChanged(); void focusInput(); void openImageOverlayInternalCb(QString eventId, QImage img); @@ -113,22 +106,6 @@ public slots: void setVideoCallItem(); - void enableBackButton() - { - if (isNarrowView_) - return; - isNarrowView_ = true; - emit narrowViewChanged(); - } - void disableBackButton() - { - if (!isNarrowView_) - return; - isNarrowView_ = false; - emit narrowViewChanged(); - } - - void backToRooms() { emit showRoomList(); } QObject *completerFor(QString completerName, QString roomId = ""); void forwardMessageToRoom(mtx::events::collections::TimelineEvents *e, QString roomId); @@ -152,7 +129,6 @@ private: CallManager *callManager_ = nullptr; bool isInitialSync_ = true; - bool isNarrowView_ = false; bool isWindowFocused_ = false; RoomlistModel *rooms_ = nullptr;