diff --git a/resources/qml/ChatPage.qml b/resources/qml/ChatPage.qml
index 0fe65afc..e5b53738 100644
--- a/resources/qml/ChatPage.qml
+++ b/resources/qml/ChatPage.qml
@@ -5,6 +5,7 @@
import QtQuick 2.9
import QtQuick.Controls 2.13
import QtQuick.Layouts 1.3
+import "components"
import im.nheko 1.0
Rectangle {
@@ -12,34 +13,48 @@ Rectangle {
color: Nheko.colors.window
- SplitView {
+ AdaptiveLayout {
anchors.fill: parent
+ singlePageMode: width < communityListC.maximumWidth + roomListC.maximumWidth + timlineViewC.minimumWidth
+
+ AdaptiveLayoutElement {
+ id: communityListC
+
+ minimumWidth: Nheko.avatarSize * 2 + Nheko.paddingSmall * 2
+ collapsedWidth: Nheko.avatarSize + Nheko.paddingSmall * 2
+ preferredWidth: Nheko.avatarSize + Nheko.paddingSmall * 2
+ maximumWidth: Nheko.avatarSize * 7 + Nheko.paddingSmall * 2
+
+ Rectangle {
+ color: Nheko.theme.sidebarBackground
+ }
- Rectangle {
- SplitView.minimumWidth: Nheko.avatarSize + Nheko.paddingSmall * 2
- SplitView.preferredWidth: Nheko.avatarSize + Nheko.paddingSmall * 2
- SplitView.maximumWidth: Nheko.avatarSize + Nheko.paddingSmall * 2
- color: Nheko.theme.sidebarBackground
}
- RoomList {
- //SplitView.maximumWidth: Nheko.avatarSize * 7 + Nheko.paddingSmall * 2
+ AdaptiveLayoutElement {
+ id: roomListC
+
+ 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
+
+ RoomList {
+ }
- SplitView.minimumWidth: Nheko.avatarSize * 5 + Nheko.paddingSmall * 2
- SplitView.preferredWidth: Nheko.avatarSize * 5 + Nheko.paddingSmall * 2
}
- TimelineView {
- id: timeline
+ AdaptiveLayoutElement {
+ id: timlineViewC
- room: Rooms.currentRoom
- SplitView.fillWidth: true
- SplitView.minimumWidth: 400
- }
+ minimumWidth: 400
+
+ TimelineView {
+ id: timeline
+
+ room: Rooms.currentRoom
+ }
- handle: Rectangle {
- implicitWidth: 2
- color: SplitHandle.pressed ? Nheko.colors.highlight : (SplitHandle.hovered ? Nheko.colors.light : Nheko.theme.separator)
}
}
diff --git a/resources/qml/RoomList.qml b/resources/qml/RoomList.qml
index ecfb3af9..ce991dec 100644
--- a/resources/qml/RoomList.qml
+++ b/resources/qml/RoomList.qml
@@ -11,6 +11,9 @@ import QtQuick.Layouts 1.3
import im.nheko 1.0
Page {
+ //leftPadding: Nheko.paddingSmall
+ //rightPadding: Nheko.paddingSmall
+
ListView {
id: roomlist
@@ -145,6 +148,7 @@ Page {
]
TapHandler {
+ margin: -2
acceptedButtons: Qt.RightButton
onSingleTapped: {
if (!TimelineManager.isInvite)
@@ -155,6 +159,7 @@ Page {
}
TapHandler {
+ margin: -2
onSingleTapped: Rooms.setCurrentRoom(model.roomId)
onLongPressed: {
if (!TimelineManager.isInvite)
@@ -164,6 +169,7 @@ Page {
}
HoverHandler {
+ margin: -2
id: hovered
}
@@ -390,6 +396,7 @@ Page {
}
TapHandler {
+ margin: -2
acceptedButtons: Qt.LeftButton
onSingleTapped: userInfoPanel.openUserProfile()
onLongPressed: userInfoMenu.open()
@@ -397,6 +404,7 @@ Page {
}
TapHandler {
+ margin: -2
acceptedButtons: Qt.RightButton
onSingleTapped: userInfoMenu.open()
gesturePolicy: TapHandler.ReleaseWithinBounds
diff --git a/resources/qml/components/AdaptiveLayout.qml b/resources/qml/components/AdaptiveLayout.qml
new file mode 100644
index 00000000..e6416414
--- /dev/null
+++ b/resources/qml/components/AdaptiveLayout.qml
@@ -0,0 +1,130 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+import QtQuick.Layouts 1.15
+import im.nheko 1.0
+
+Container {
+ //Component.onCompleted: {
+ // parent.width = Qt.binding(function() { return calculatedWidth; })
+ //}
+
+ id: container
+
+ property bool singlePageMode: width < 800
+ property int splitterGrabMargin: Nheko.paddingSmall
+ property int pageIndex: 0
+ property Component handle
+
+ handle: Rectangle {
+ z: 3
+ color: Nheko.theme.separator
+ height: container.height
+ width: visible ? 1 : 0
+ anchors.right: parent.right
+ }
+
+ property Component handleToucharea
+
+ handleToucharea: Item {
+ id: splitter
+
+ property int minimumWidth: parent.minimumWidth
+ property int maximumWidth: parent.maximumWidth
+ property int collapsedWidth: parent.collapsedWidth
+ property bool collapsible: parent.collapsible
+ property int calculatedWidth: {
+ if (!visible)
+ return 0;
+ else if (container.singlePageMode)
+ return container.width;
+ else
+ return (collapsible && x < minimumWidth) ? collapsedWidth : x;
+ }
+
+ //visible: !container.singlePageMode
+ enabled: !container.singlePageMode
+ height: container.height
+ width: 1
+ x: parent.preferredWidth
+ z: 3
+
+ DragHandler {
+ id: dragHandler
+
+ enabled: !container.singlePageMode
+ xAxis.enabled: true
+ yAxis.enabled: false
+ xAxis.minimum: splitter.minimumWidth - 1
+ xAxis.maximum: splitter.maximumWidth
+ margin: container.splitterGrabMargin
+ dragThreshold: 0
+ grabPermissions: PointerHandler.CanTakeOverFromAnything | PointerHandler.ApprovesTakeOverByHandlersOfSameType
+ cursorShape: Qt.SizeHorCursor
+ onActiveChanged: {
+ if (!active)
+ splitter.parent.preferredWidth = splitter.x;
+
+ }
+ }
+
+ HoverHandler {
+ enabled: !container.singlePageMode
+ margin: container.splitterGrabMargin
+ cursorShape: Qt.SizeHorCursor
+ }
+
+ }
+
+ 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
+
+ model: container.contentModel
+ snapMode: ListView.SnapOneItem
+ orientation: ListView.Horizontal
+ highlightRangeMode: ListView.StrictlyEnforceRange
+ interactive: false
+ highlightMoveDuration: container.singlePageMode ? 200 : 0
+ currentIndex: container.singlePageMode ? container.pageIndex : 0
+ }
+
+}
diff --git a/resources/qml/components/AdaptiveLayoutElement.qml b/resources/qml/components/AdaptiveLayoutElement.qml
new file mode 100644
index 00000000..411f6c64
--- /dev/null
+++ b/resources/qml/components/AdaptiveLayoutElement.qml
@@ -0,0 +1,26 @@
+// SPDX-FileCopyrightText: 2021 Nheko Contributors
+//
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+import QtQuick 2.15
+import QtQuick.Controls 2.15
+import QtQuick.Layouts 1.15
+
+Item {
+ property int minimumWidth: 100
+ property int maximumWidth: 400
+ property int collapsedWidth: 40
+ property bool collapsible: true
+ property bool collapsed: width < minimumWidth
+ property int splitterWidth: 1
+ property int preferredWidth: 100
+
+ Component.onCompleted: {
+ children[0].width = Qt.binding(() => {
+ return parent.singlePageMode ? parent.width : width - splitterWidth;
+ });
+ children[0].height = Qt.binding(() => {
+ return parent.height;
+ });
+ }
+}
diff --git a/resources/res.qrc b/resources/res.qrc
index 183cf394..531e9be2 100644
--- a/resources/res.qrc
+++ b/resources/res.qrc
@@ -178,6 +178,8 @@
qml/voip/PlaceCall.qml
qml/voip/ScreenShare.qml
qml/voip/VideoCall.qml
+ qml/components/AdaptiveLayout.qml
+ qml/components/AdaptiveLayoutElement.qml
media/ring.ogg