Implement switching in narrow mode

This commit is contained in:
Nicolas Werner 2021-06-08 22:18:51 +02:00
parent 686298e023
commit d364c29c43
No known key found for this signature in database
GPG key ID: C8D75E610773F2D9
8 changed files with 109 additions and 77 deletions

View file

@ -14,8 +14,11 @@ Rectangle {
color: Nheko.colors.window color: Nheko.colors.window
AdaptiveLayout { AdaptiveLayout {
id: adaptiveView
anchors.fill: parent anchors.fill: parent
singlePageMode: width < communityListC.maximumWidth + roomListC.maximumWidth + timlineViewC.minimumWidth singlePageMode: width < communityListC.maximumWidth + roomListC.maximumWidth + timlineViewC.minimumWidth
pageIndex: Rooms.currentRoom ? 2 : 1
AdaptiveLayoutElement { AdaptiveLayoutElement {
id: communityListC id: communityListC
@ -37,9 +40,12 @@ Rectangle {
minimumWidth: Nheko.avatarSize * 5 + Nheko.paddingSmall * 2 minimumWidth: Nheko.avatarSize * 5 + Nheko.paddingSmall * 2
preferredWidth: Nheko.avatarSize * 5 + Nheko.paddingSmall * 2 preferredWidth: Nheko.avatarSize * 5 + Nheko.paddingSmall * 2
maximumWidth: Nheko.avatarSize * 10 + Nheko.paddingSmall * 2 maximumWidth: Nheko.avatarSize * 10 + Nheko.paddingSmall * 2
collapsedWidth: Nheko.avatarSize + Nheko.paddingSmall * 2 collapsedWidth: roomlist.avatarSize + 2 * Nheko.paddingMedium
RoomList { RoomList {
id: roomlist
collapsed: parent.collapsed
} }
} }
@ -52,6 +58,7 @@ Rectangle {
TimelineView { TimelineView {
id: timeline id: timeline
showBackButton: adaptiveView.singlePageMode
room: Rooms.currentRoom room: Rooms.currentRoom
} }

View file

@ -13,6 +13,8 @@ import im.nheko 1.0
Page { Page {
//leftPadding: Nheko.paddingSmall //leftPadding: Nheko.paddingSmall
//rightPadding: Nheko.paddingSmall //rightPadding: Nheko.paddingSmall
property int avatarSize: Math.ceil(fontMetrics.lineSpacing * 2.3)
property bool collapsed: false
ListView { ListView {
id: roomlist id: roomlist
@ -113,9 +115,11 @@ Page {
property color bubbleText: Nheko.colors.highlightedText property color bubbleText: Nheko.colors.highlightedText
color: background color: background
height: Math.ceil(fontMetrics.lineSpacing * 2.3 + Nheko.paddingMedium * 2) height: avatarSize + 2 * Nheko.paddingMedium
width: ListView.view.width width: ListView.view.width
state: "normal" state: "normal"
ToolTip.visible: hovered.hovered && collapsed
ToolTip.text: model.roomName
states: [ states: [
State { State {
name: "highlight" name: "highlight"
@ -148,7 +152,7 @@ Page {
] ]
TapHandler { TapHandler {
margin: -2 margin: -Nheko.paddingSmall
acceptedButtons: Qt.RightButton acceptedButtons: Qt.RightButton
onSingleTapped: { onSingleTapped: {
if (!TimelineManager.isInvite) if (!TimelineManager.isInvite)
@ -159,7 +163,7 @@ Page {
} }
TapHandler { TapHandler {
margin: -2 margin: -Nheko.paddingSmall
onSingleTapped: Rooms.setCurrentRoom(model.roomId) onSingleTapped: Rooms.setCurrentRoom(model.roomId)
onLongPressed: { onLongPressed: {
if (!TimelineManager.isInvite) if (!TimelineManager.isInvite)
@ -169,8 +173,9 @@ Page {
} }
HoverHandler { HoverHandler {
margin: -2
id: hovered id: hovered
margin: -Nheko.paddingSmall
} }
RowLayout { RowLayout {
@ -186,15 +191,46 @@ Page {
enabled: false enabled: false
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
height: Math.ceil(fontMetrics.lineSpacing * 2.3) height: avatarSize
width: Math.ceil(fontMetrics.lineSpacing * 2.3) width: avatarSize
url: model.avatarUrl.replace("mxc://", "image://MxcImage/") url: model.avatarUrl.replace("mxc://", "image://MxcImage/")
displayName: model.roomName 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 { ColumnLayout {
id: textContent id: textContent
visible: !collapsed
Layout.alignment: Qt.AlignLeft Layout.alignment: Qt.AlignLeft
Layout.fillWidth: true Layout.fillWidth: true
Layout.minimumWidth: 100 Layout.minimumWidth: 100
@ -396,7 +432,7 @@ Page {
} }
TapHandler { TapHandler {
margin: -2 margin: -Nheko.paddingSmall
acceptedButtons: Qt.LeftButton acceptedButtons: Qt.LeftButton
onSingleTapped: userInfoPanel.openUserProfile() onSingleTapped: userInfoPanel.openUserProfile()
onLongPressed: userInfoMenu.open() onLongPressed: userInfoMenu.open()
@ -404,7 +440,7 @@ Page {
} }
TapHandler { TapHandler {
margin: -2 margin: -Nheko.paddingSmall
acceptedButtons: Qt.RightButton acceptedButtons: Qt.RightButton
onSingleTapped: userInfoMenu.open() onSingleTapped: userInfoMenu.open()
gesturePolicy: TapHandler.ReleaseWithinBounds gesturePolicy: TapHandler.ReleaseWithinBounds
@ -431,6 +467,7 @@ Page {
ColumnLayout { ColumnLayout {
id: col id: col
visible: !collapsed
Layout.alignment: Qt.AlignLeft Layout.alignment: Qt.AlignLeft
Layout.fillWidth: true Layout.fillWidth: true
width: parent.width - avatar.width - logoutButton.width - Nheko.paddingMedium * 2 width: parent.width - avatar.width - logoutButton.width - Nheko.paddingMedium * 2
@ -462,6 +499,7 @@ Page {
ImageButton { ImageButton {
id: logoutButton id: logoutButton
visible: !collapsed
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
image: ":/icons/icons/ui/power-button-off.png" image: ":/icons/icons/ui/power-button-off.png"
ToolTip.visible: hovered ToolTip.visible: hovered
@ -533,6 +571,7 @@ Page {
} }
ImageButton { ImageButton {
visible: !collapsed
Layout.alignment: Qt.AlignBottom | Qt.AlignHCenter Layout.alignment: Qt.AlignBottom | Qt.AlignHCenter
hoverEnabled: true hoverEnabled: true
width: 22 width: 22
@ -544,6 +583,7 @@ Page {
} }
ImageButton { ImageButton {
visible: !collapsed
Layout.alignment: Qt.AlignBottom | Qt.AlignRight Layout.alignment: Qt.AlignBottom | Qt.AlignRight
hoverEnabled: true hoverEnabled: true
width: 22 width: 22

View file

@ -19,6 +19,7 @@ Item {
id: timelineView id: timelineView
property var room: null property var room: null
property bool showBackButton: false
Label { Label {
visible: !room && !TimelineManager.isInitialSync visible: !room && !TimelineManager.isInitialSync
@ -45,6 +46,7 @@ Item {
spacing: 0 spacing: 0
TopBar { TopBar {
showBackButton: timelineView.showBackButton
} }
Rectangle { Rectangle {

View file

@ -11,6 +11,8 @@ import im.nheko 1.0
Rectangle { Rectangle {
id: topBar id: topBar
property bool showBackButton: false
Layout.fillWidth: true Layout.fillWidth: true
implicitHeight: topLayout.height + Nheko.paddingMedium * 2 implicitHeight: topLayout.height + Nheko.paddingMedium * 2
z: 3 z: 3
@ -43,11 +45,11 @@ Rectangle {
Layout.alignment: Qt.AlignVCenter Layout.alignment: Qt.AlignVCenter
width: Nheko.avatarSize width: Nheko.avatarSize
height: Nheko.avatarSize height: Nheko.avatarSize
visible: TimelineManager.isNarrowView visible: showBackButton
image: ":/icons/icons/ui/angle-pointing-to-left.png" image: ":/icons/icons/ui/angle-pointing-to-left.png"
ToolTip.visible: hovered ToolTip.visible: hovered
ToolTip.text: qsTr("Back to room list") ToolTip.text: qsTr("Back to room list")
onClicked: TimelineManager.backToRooms() onClicked: Rooms.resetCurrentRoom()
} }
Avatar { Avatar {

View file

@ -18,6 +18,43 @@ Container {
property int splitterGrabMargin: Nheko.paddingSmall property int splitterGrabMargin: Nheko.paddingSmall
property int pageIndex: 0 property int pageIndex: 0
property Component handle 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 { handle: Rectangle {
z: 3 z: 3
@ -27,8 +64,6 @@ Container {
anchors.right: parent.right anchors.right: parent.right
} }
property Component handleToucharea
handleToucharea: Item { handleToucharea: Item {
id: splitter 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 { contentItem: ListView {
id: view id: view

View file

@ -21,7 +21,8 @@ class TimelineViewManager;
class RoomlistModel : public QAbstractListModel class RoomlistModel : public QAbstractListModel
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(TimelineModel *currentRoom READ currentRoom NOTIFY currentRoomChanged) Q_PROPERTY(TimelineModel *currentRoom READ currentRoom NOTIFY currentRoomChanged RESET
resetCurrentRoom)
public: public:
enum Roles enum Roles
{ {
@ -73,6 +74,11 @@ public slots:
void leave(QString roomid); void leave(QString roomid);
TimelineModel *currentRoom() const { return currentRoom_.get(); } TimelineModel *currentRoom() const { return currentRoom_.get(); }
void setCurrentRoom(QString roomid); void setCurrentRoom(QString roomid);
void resetCurrentRoom()
{
currentRoom_ = nullptr;
emit currentRoomChanged();
}
private slots: private slots:
void updateReadStatus(const std::map<QString, bool> roomReadStatus_); void updateReadStatus(const std::map<QString, bool> roomReadStatus_);
@ -98,7 +104,8 @@ private:
class FilteredRoomlistModel : public QSortFilterProxyModel class FilteredRoomlistModel : public QSortFilterProxyModel
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(TimelineModel *currentRoom READ currentRoom NOTIFY currentRoomChanged) Q_PROPERTY(TimelineModel *currentRoom READ currentRoom NOTIFY currentRoomChanged RESET
resetCurrentRoom)
public: public:
FilteredRoomlistModel(RoomlistModel *model, QObject *parent = nullptr); FilteredRoomlistModel(RoomlistModel *model, QObject *parent = nullptr);
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
@ -117,6 +124,7 @@ public slots:
TimelineModel *currentRoom() const { return roomlistmodel->currentRoom(); } TimelineModel *currentRoom() const { return roomlistmodel->currentRoom(); }
void setCurrentRoom(QString roomid) { roomlistmodel->setCurrentRoom(std::move(roomid)); } void setCurrentRoom(QString roomid) { roomlistmodel->setCurrentRoom(std::move(roomid)); }
void resetCurrentRoom() { roomlistmodel->resetCurrentRoom(); }
void nextRoom(); void nextRoom();
void previousRoom(); void previousRoom();

View file

@ -891,7 +891,6 @@ TimelineModel::updateLastMessage()
time}; time};
if (description != lastMessage_) { if (description != lastMessage_) {
lastMessage_ = description; lastMessage_ = description;
emit manager_->updateRoomsLastMessage(room_id_, lastMessage_);
emit lastMessageChanged(); emit lastMessageChanged();
} }
return; return;
@ -906,7 +905,6 @@ TimelineModel::updateLastMessage()
QString::fromStdString(mtx::accessors::sender(*event)))); QString::fromStdString(mtx::accessors::sender(*event))));
if (description != lastMessage_) { if (description != lastMessage_) {
lastMessage_ = description; lastMessage_ = description;
emit manager_->updateRoomsLastMessage(room_id_, description);
emit lastMessageChanged(); emit lastMessageChanged();
} }
return; return;

View file

@ -37,8 +37,6 @@ class TimelineViewManager : public QObject
Q_PROPERTY( Q_PROPERTY(
bool isInitialSync MEMBER isInitialSync_ READ isInitialSync NOTIFY initialSyncChanged) bool isInitialSync MEMBER isInitialSync_ READ isInitialSync NOTIFY initialSyncChanged)
Q_PROPERTY(
bool isNarrowView MEMBER isNarrowView_ READ isNarrowView NOTIFY narrowViewChanged)
Q_PROPERTY( Q_PROPERTY(
bool isWindowFocused MEMBER isWindowFocused_ READ isWindowFocused NOTIFY focusChanged) bool isWindowFocused MEMBER isWindowFocused_ READ isWindowFocused NOTIFY focusChanged)
@ -54,7 +52,6 @@ public:
void clearAll() { rooms_->clear(); } void clearAll() { rooms_->clear(); }
Q_INVOKABLE bool isInitialSync() const { return isInitialSync_; } Q_INVOKABLE bool isInitialSync() const { return isInitialSync_; }
bool isNarrowView() const { return isNarrowView_; }
bool isWindowFocused() const { return isWindowFocused_; } bool isWindowFocused() const { return isWindowFocused_; }
Q_INVOKABLE void openImageOverlay(QString mxcUrl, QString eventId); Q_INVOKABLE void openImageOverlay(QString mxcUrl, QString eventId);
Q_INVOKABLE QColor userColor(QString id, QColor background); Q_INVOKABLE QColor userColor(QString id, QColor background);
@ -74,16 +71,12 @@ public:
void verifyDevice(QString userid, QString deviceid); void verifyDevice(QString userid, QString deviceid);
signals: signals:
void clearRoomMessageCount(QString roomid);
void updateRoomsLastMessage(QString roomid, const DescInfo &info);
void activeTimelineChanged(TimelineModel *timeline); void activeTimelineChanged(TimelineModel *timeline);
void initialSyncChanged(bool isInitialSync); void initialSyncChanged(bool isInitialSync);
void replyingEventChanged(QString replyingEvent); void replyingEventChanged(QString replyingEvent);
void replyClosed(); void replyClosed();
void newDeviceVerificationRequest(DeviceVerificationFlow *flow); void newDeviceVerificationRequest(DeviceVerificationFlow *flow);
void inviteUsers(QStringList users); void inviteUsers(QStringList users);
void showRoomList();
void narrowViewChanged();
void focusChanged(); void focusChanged();
void focusInput(); void focusInput();
void openImageOverlayInternalCb(QString eventId, QImage img); void openImageOverlayInternalCb(QString eventId, QImage img);
@ -113,22 +106,6 @@ public slots:
void setVideoCallItem(); 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 = ""); QObject *completerFor(QString completerName, QString roomId = "");
void forwardMessageToRoom(mtx::events::collections::TimelineEvents *e, QString roomId); void forwardMessageToRoom(mtx::events::collections::TimelineEvents *e, QString roomId);
@ -152,7 +129,6 @@ private:
CallManager *callManager_ = nullptr; CallManager *callManager_ = nullptr;
bool isInitialSync_ = true; bool isInitialSync_ = true;
bool isNarrowView_ = false;
bool isWindowFocused_ = false; bool isWindowFocused_ = false;
RoomlistModel *rooms_ = nullptr; RoomlistModel *rooms_ = nullptr;