pragma ComponentBehavior: Bound import ".." import qs.components import qs.components.controls import qs.components.containers import qs.services import qs.config import QtQuick import QtQuick.Layouts /** * DeviceList * * A reusable base component for displaying lists of devices/networks with a standardized * structure. Provides a header with action buttons, title/subtitle, and a scrollable list * with customizable delegates. * * This component eliminates duplication across WirelessList, EthernetList, and Bluetooth DeviceList * by providing a common structure while allowing full customization of headers and delegates. * * Usage: * ```qml * DeviceList { * session: root.session * title: qsTr("Networks (%1)").arg(Nmcli.networks.length) * description: qsTr("All available WiFi networks") * model: ScriptModel { * values: [...Nmcli.networks].sort(...) * } * activeItem: session.network.active * onItemSelected: (item) => { * session.network.active = item; * } * headerComponent: Component { * RowLayout { * // Custom header buttons * } * } * delegate: Component { * // Custom delegate for each item * } * } * ``` */ ColumnLayout { id: root property Session session: null property var model: null property Component delegate: null property string title: "" property string description: "" property var activeItem: null property Component headerComponent: null property Component titleSuffix: null signal itemSelected(var item) spacing: Appearance.spacing.small // Header with action buttons (optional) Loader { id: headerLoader Layout.fillWidth: true sourceComponent: root.headerComponent visible: root.headerComponent !== null } // Title and description row RowLayout { Layout.fillWidth: true Layout.topMargin: root.headerComponent ? 0 : 0 spacing: Appearance.spacing.small visible: root.title !== "" || root.description !== "" StyledText { visible: root.title !== "" text: root.title font.pointSize: Appearance.font.size.large font.weight: 500 } Loader { sourceComponent: root.titleSuffix visible: root.titleSuffix !== null } Item { Layout.fillWidth: true } } // Expose view for access from parent components property alias view: view // Description text StyledText { visible: root.description !== "" Layout.fillWidth: true text: root.description color: Colours.palette.m3outline } // List view StyledListView { id: view Layout.fillWidth: true Layout.fillHeight: true model: root.model delegate: root.delegate spacing: Appearance.spacing.small / 2 clip: true StyledScrollBar.vertical: StyledScrollBar { flickable: view } } }