From 2ffb0feeddd91c4a07c52564ad17aea6393729e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Cie=C5=9Blak?= Date: Fri, 16 Feb 2024 11:52:21 +0100 Subject: [PATCH] feat(Storybook): Utility allowing quickly visualize any model. It makes work with model in Storybook much faster bc eliminates work related to creating delegates and also (when needed) handling dnd logic. Closes: #13599 --- storybook/src/Storybook/GenericListView.qml | 162 ++++++++++++++++++++ storybook/src/Storybook/qmldir | 1 + 2 files changed, 163 insertions(+) create mode 100644 storybook/src/Storybook/GenericListView.qml diff --git a/storybook/src/Storybook/GenericListView.qml b/storybook/src/Storybook/GenericListView.qml new file mode 100644 index 0000000000..c8e326f35e --- /dev/null +++ b/storybook/src/Storybook/GenericListView.qml @@ -0,0 +1,162 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.15 + +import StatusQ.Core.Utils 0.1 + +import utils 1.0 + +ListView { + id: root + + // adds drag handler to every row, emits moveRequested when item is moved + property bool movable: false + + // roles intended to be visualized, all roles when empty + property var roles: [] + + // custom delegate height, when set to 0, delegate's implicitHeight is used + property int delegateHeight: 0 + + // text to be displayed in a list view's header + property string label + + // additional component to be instantiated within every delegate + property Component insetComponent + + property int margin: 5 + + ScrollBar.vertical: ScrollBar {} + + clip: true + spacing: 5 + + leftMargin: margin + rightMargin: margin + topMargin: margin + bottomMargin: margin + + signal moveRequested(int from, int to) + + ListModel { + id: rowModel + + function initialize() { + const roleNames = roles.length ? roles + : ModelUtils.roleNames(root.model) + const modelContent = roleNames.map(roleName => ({ roleName })) + + clear() + append(modelContent) + } + + Component.onCompleted: initialize() + } + + Rectangle { + border.color: "lightgray" + color: "transparent" + anchors.fill: parent + } + + header: Label { + visible: !!text + height: visible ? undefined : 0 + text: root.label + font.bold: true + font.pixelSize: 16 + bottomPadding: 20 + } + + delegate: Item { + id: delegateRoot + + width: ListView.view.width + height: root.delegateHeight || delegateRow.implicitHeight + + readonly property var topModel: model + + RowLayout { + id: delegateRow + + Drag.active: dragArea.pressed + Drag.source: dragArea + Drag.hotSpot.x: width / 2 + Drag.hotSpot.y: height / 2 + + states: State { + when: dragArea.pressed + + ParentChange { + target: delegateRow + parent: root + } + + AnchorChanges { + target: delegateRow + anchors { + horizontalCenter: undefined + verticalCenter: undefined + } + } + } + + RoundButton { + text: "↕️" + visible: root.movable + + MouseArea { + id: dragArea + + property bool held: pressed + readonly property int idx: model.index + + anchors.fill: parent + + drag.target: pressed ? delegateRow : undefined + drag.axis: Drag.YAxis + } + } + + Repeater { + model: rowModel + + Label { + readonly property var value: + delegateRoot.topModel[roleName] + + readonly property var valueSanitized: + value === undefined ? "-" : value + + readonly property bool last: index === rowModel.count - 1 + readonly property string separator: last ? "" : "," + + text: `${roleName}: ${valueSanitized}${separator}` + } + } + + Loader { + readonly property var model: delegateRoot.topModel + sourceComponent: insetComponent + } + + Item { + Layout.fillWidth: true + } + } + + DropArea { + anchors { fill: parent; margins: 10 } + + onEntered: { + const from = drag.source.idx + const to = dragArea.idx + + if (from === to) + return + + root.moveRequested(from, to) + } + } + } +} diff --git a/storybook/src/Storybook/qmldir b/storybook/src/Storybook/qmldir index 53632a3e14..1721822b27 100644 --- a/storybook/src/Storybook/qmldir +++ b/storybook/src/Storybook/qmldir @@ -4,6 +4,7 @@ FigmaLinksCache 1.0 FigmaLinksCache.qml FigmaPreviewWindow 1.0 FigmaPreviewWindow.qml FilteredPagesList 1.0 FilteredPagesList.qml FlickableImage 1.0 FlickableImage.qml +GenericListView 1.0 GenericListView.qml HotComponentFromSource 1.0 HotComponentFromSource.qml HotLoader 1.0 HotLoader.qml HotReloader 1.0 HotReloader.qml