From 77d8878428f916e6107a88479d66b27e33ffeaf5 Mon Sep 17 00:00:00 2001 From: Andrea Bogazzi Date: Sun, 24 May 2026 23:10:58 +0200 Subject: [PATCH 1/4] good enough --- resources/images/logo-crt.png | Bin 0 -> 21060 bytes rust/launcher/.qmlls.ini | 3 + scripts/run-macos-mister-core.sh | 2 +- src/ui/app/MainLayout.qml | 14 +++- src/ui/components/BrowseDetailPane.qml | 50 +++++++++----- src/ui/components/BrowseList.qml | 75 ++++++++++++--------- src/ui/components/BrowseListDetailView.qml | 9 ++- src/ui/components/HeaderBar.qml | 20 ++++++ src/ui/components/TopStatusStrip.qml | 10 +-- src/ui/screens/FavoritesScreen.qml | 1 + src/ui/screens/MediaListScreen.qml | 12 ++-- src/ui/screens/RecentsScreen.qml | 1 + src/ui/screens/SystemsScreen.qml | 20 +++--- src/ui/theme/BrowseLayouts.qml | 66 +++++++++++++++++- 14 files changed, 207 insertions(+), 76 deletions(-) create mode 100644 resources/images/logo-crt.png create mode 100644 rust/launcher/.qmlls.ini diff --git a/resources/images/logo-crt.png b/resources/images/logo-crt.png new file mode 100644 index 0000000000000000000000000000000000000000..c27006cd73f9bb63fcd7fd041f2d26406975cdf7 GIT binary patch literal 21060 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ⅇ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 T(|io=00000NkvXXu0mjf)IZ+) literal 0 HcmV?d00001 diff --git a/rust/launcher/.qmlls.ini b/rust/launcher/.qmlls.ini new file mode 100644 index 0000000..49a0cf3 --- /dev/null +++ b/rust/launcher/.qmlls.ini @@ -0,0 +1,3 @@ +[General] +buildDir="/tmp/zaparoo-target/cxxqt/qml_modules" +no-cmake-calls=true diff --git a/scripts/run-macos-mister-core.sh b/scripts/run-macos-mister-core.sh index c227472..01d38be 100755 --- a/scripts/run-macos-mister-core.sh +++ b/scripts/run-macos-mister-core.sh @@ -17,5 +17,5 @@ fi export ZAPAROO_CORE_ENDPOINT="ws://192.168.1.176:7497/api/v0.1" export ZAPAROO_CRT_PREVIEW_SCALE=3 -exec "${FRONTEND}" +exec "${FRONTEND}" --crt # exec "${FRONTEND}" --crt diff --git a/src/ui/app/MainLayout.qml b/src/ui/app/MainLayout.qml index 8c10079..0c45d4a 100644 --- a/src/ui/app/MainLayout.qml +++ b/src/ui/app/MainLayout.qml @@ -287,7 +287,7 @@ ApplicationWindow { readonly property string recentsScreenState: Browse.RecentsModel.loading ? "loading" : ((Browse.RecentsModel.error_message ?? "") !== "" ? "error" : (Browse.RecentsModel.count === 0 ? "empty" : "ready")) readonly property bool _crtGridBrowseLayout: root.crtNativePath && Browse.Settings.current_browse_layout !== "list" - readonly property var _browseTileLayout: root._crtGridBrowseLayout ? BrowseLayouts.crtTile : BrowseLayouts.defaultTile + readonly property var _browseTileLayout: root.crtNativePath ? BrowseLayouts.crtTile : BrowseLayouts.defaultTile readonly property var _contextMenuLayout: root.crtNativePath ? BrowseLayouts.crtTile : BrowseLayouts.defaultTile readonly property string _crtGamesHeaderTitle: { const sid = Browse.GamesModel.current_system_id; @@ -297,12 +297,21 @@ ApplicationWindow { return idx >= 0 ? Browse.SystemsModel.system_name_at(idx) : sid; } readonly property string browseHeaderTitle: { - if (!root._crtGridBrowseLayout) + if (!root.crtNativePath) + return ""; + if (Browse.Settings.current_browse_layout === "list") return ""; if (root.activeScreen === root.screenSystems) return Browse.SystemsModel.current_category; if (root.activeScreen === root.screenGames) return root._crtGamesHeaderTitle; + if (root.activeScreen === root.screenFavorites) + return qsTr("Favorites"); + if (root.activeScreen === root.screenRecents) + return qsTr("Recently Played"); + return ""; + } + readonly property string browseHeaderProgressText: { return ""; } @@ -427,6 +436,7 @@ ApplicationWindow { anchors.topMargin: Sizing.headerTopMargin layoutProfile: root._browseTileLayout browseTitle: root.browseHeaderTitle + browseProgressText: root.browseHeaderProgressText z: 200 } diff --git a/src/ui/components/BrowseDetailPane.qml b/src/ui/components/BrowseDetailPane.qml index b71c347..82f4ef9 100644 --- a/src/ui/components/BrowseDetailPane.qml +++ b/src/ui/components/BrowseDetailPane.qml @@ -21,17 +21,20 @@ Item { property bool detailSuppressed: false property bool showChrome: true property string loadingText: qsTr("Loading…") + property var layoutProfile: null - readonly property int _cardPaddingX: Sizing.pctW(2) - readonly property int _cardPaddingY: Sizing.pctH(2) + readonly property int _cardPaddingLeft: root.layoutProfile && root.layoutProfile.detailPanePaddingLeft !== undefined ? root.layoutProfile.detailPanePaddingLeft : Sizing.pctW(2) + readonly property int _cardPaddingRight: root.layoutProfile && root.layoutProfile.detailPanePaddingRight !== undefined ? root.layoutProfile.detailPanePaddingRight : Sizing.pctW(2) + readonly property int _cardPaddingTop: root.layoutProfile && root.layoutProfile.detailPanePaddingTop !== undefined ? root.layoutProfile.detailPanePaddingTop : Sizing.pctH(2) + readonly property int _cardPaddingBottom: root.layoutProfile && root.layoutProfile.detailPanePaddingBottom !== undefined ? root.layoutProfile.detailPanePaddingBottom : Sizing.pctH(2) readonly property int _carouselGutter: (canPreviousImage || canNextImage) ? Sizing.pctW(4) : 0 property int _labelColumnWidth: 0 readonly property int _tagTextSize: Sizing.fontSize(2.2) readonly property int _tagLabelGap: Sizing.pctW(1.4) readonly property var _detailRows: _parseDetailTags(detailTags) readonly property int _tagRowCount: _detailRows.length - readonly property int _tagRowHeight: Sizing.pctH(3) - readonly property int _tagRowSpacing: Sizing.pctH(0.55) + readonly property int _tagRowHeight: root.layoutProfile && root.layoutProfile.detailTagRowHeight !== undefined ? root.layoutProfile.detailTagRowHeight : Sizing.pctH(3) + readonly property int _tagRowSpacing: root.layoutProfile && root.layoutProfile.detailTagRowSpacing !== undefined ? root.layoutProfile.detailTagRowSpacing : Sizing.pctH(0.55) readonly property int _metadataNaturalHeight: _tagRowCount <= 0 ? 0 : (_tagRowCount * _tagRowHeight) + ((_tagRowCount - 1) * _tagRowSpacing) readonly property int _compactDetailHeight: Math.min(Sizing.px(content.height * 0.38), _metadataNaturalHeight) readonly property bool _coverPending: coverKey === "icons/Loading" @@ -39,6 +42,16 @@ Item { readonly property bool _paneLoading: root.loading readonly property bool _detailVisible: !root._paneLoading && !root.detailSuppressed readonly property bool _suppressedPlaceholderCover: root.detailSuppressed && coverKey.startsWith("icons/") && root._coverSource !== "" + readonly property int _metadataYOffset: root.layoutProfile && root.layoutProfile.detailMetadataYOffset !== undefined ? root.layoutProfile.detailMetadataYOffset : 0 + readonly property int _metadataExtraHeight: root.layoutProfile && root.layoutProfile.detailMetadataExtraHeight !== undefined ? root.layoutProfile.detailMetadataExtraHeight : 0 + readonly property int _metadataLeftInset: root.layoutProfile && root.layoutProfile.detailMetadataLeftInset !== undefined ? root.layoutProfile.detailMetadataLeftInset : 0 + readonly property int _metadataRightInset: root.layoutProfile && root.layoutProfile.detailMetadataRightInset !== undefined ? root.layoutProfile.detailMetadataRightInset : 0 + readonly property int _imageXOffset: root.layoutProfile && root.layoutProfile.detailImageXOffset !== undefined ? root.layoutProfile.detailImageXOffset : 0 + readonly property int _imageLeftInset: root.layoutProfile && root.layoutProfile.detailImageLeftInset !== undefined ? root.layoutProfile.detailImageLeftInset : 0 + readonly property int _imageRightInset: root.layoutProfile && root.layoutProfile.detailImageRightInset !== undefined ? root.layoutProfile.detailImageRightInset : 0 + readonly property int _imageExtraWidth: root.layoutProfile && root.layoutProfile.detailImageExtraWidth !== undefined ? root.layoutProfile.detailImageExtraWidth : 0 + readonly property int _imageExtraHeight: root.layoutProfile && root.layoutProfile.detailImageExtraHeight !== undefined ? root.layoutProfile.detailImageExtraHeight : 0 + readonly property int _imageBottomGap: root.layoutProfile && root.layoutProfile.detailImageBottomGap !== undefined ? root.layoutProfile.detailImageBottomGap : 0 onDetailTagsChanged: root._labelColumnWidth = 0 @@ -91,23 +104,24 @@ Item { id: content anchors.fill: parent - anchors.leftMargin: root._cardPaddingX - anchors.rightMargin: root._cardPaddingX - anchors.topMargin: root._cardPaddingY - anchors.bottomMargin: root._cardPaddingY + anchors.leftMargin: root._cardPaddingLeft + anchors.rightMargin: root._cardPaddingRight + anchors.topMargin: root._cardPaddingTop + anchors.bottomMargin: root._cardPaddingBottom clip: true Item { id: imageSlot - readonly property int availableWidth: Math.max(0, parent.width - (2 * root._carouselGutter)) - readonly property int availableHeight: Math.max(0, root.showTitle ? Sizing.px(parent.height * 0.48) : detailBody.y - Sizing.pctH(1)) - readonly property int slotSize: Math.min(availableWidth, availableHeight) + readonly property int availableWidth: Math.max(0, parent.width - root._imageLeftInset - root._imageRightInset - (2 * root._carouselGutter)) + readonly property int availableHeight: Math.max(0, root.showTitle ? Sizing.px(parent.height * 0.48) : detailBody.y - root._imageBottomGap) + readonly property int slotWidth: Math.min(parent.width - root._imageLeftInset - root._imageRightInset, availableWidth + root._imageExtraWidth) + readonly property int slotHeight: Math.min(parent.height, Math.min(availableWidth, availableHeight) + root._imageExtraHeight) - x: root._carouselGutter + Sizing.center(availableWidth, width) + x: root._imageLeftInset + root._carouselGutter + root._imageXOffset anchors.top: parent.top - width: slotSize - height: slotSize + width: Math.max(0, slotWidth) + height: slotHeight Image { id: cover @@ -181,10 +195,10 @@ Item { readonly property int _bodyY: Math.round(root.showTitle ? (titleText.visible ? titleText.y + titleText.height : imageSlot.y + imageSlot.height) + Sizing.pctH(2) : parent.height - height) - x: 0 - y: _bodyY - width: parent.width - height: root.showTitle ? Math.round(Math.max(0, parent.height - _bodyY)) : root._compactDetailHeight + x: root._metadataLeftInset + y: _bodyY + root._metadataYOffset + width: Math.max(0, parent.width - root._metadataLeftInset - root._metadataRightInset) + height: root.showTitle ? Math.round(Math.max(0, parent.height - y + root._metadataExtraHeight)) : root._compactDetailHeight clip: true Column { diff --git a/src/ui/components/BrowseList.qml b/src/ui/components/BrowseList.qml index 430b89a..9d72ac9 100644 --- a/src/ui/components/BrowseList.qml +++ b/src/ui/components/BrowseList.qml @@ -17,22 +17,33 @@ Item { property int targetVisibleRowCount: 0 property bool showFileStem: false property bool showChrome: true + property var layoutProfile: null readonly property int itemCount: listView.count readonly property int totalItems: totalItemsOverride >= 0 ? totalItemsOverride : itemCount - readonly property int cardPaddingX: Sizing.pctW(2) - readonly property int cardPaddingY: Sizing.pctH(2) - readonly property int rowSpacing: Sizing.pctH(0.7) - readonly property int contentHeight: Math.max(0, height - (2 * cardPaddingY)) - readonly property int rowHeight: targetVisibleRowCount > 0 ? Math.max(Sizing.pctH(3), Math.floor((contentHeight - (rowSpacing * (targetVisibleRowCount - 1))) / targetVisibleRowCount)) : Sizing.pctH(6) + readonly property int _selectionRadius: root.layoutProfile ? root.layoutProfile.tileCornerRadius : Sizing.cornerRadius + readonly property int cardPaddingLeft: root.layoutProfile ? root.layoutProfile.listCardPaddingLeft : Sizing.pctW(2) + readonly property int cardPaddingRight: root.layoutProfile ? root.layoutProfile.listCardPaddingRight : Sizing.pctW(2) + readonly property int cardPaddingTop: root.layoutProfile ? root.layoutProfile.listCardPaddingTop : Sizing.pctH(2) + readonly property int cardPaddingBottom: root.layoutProfile ? root.layoutProfile.listCardPaddingBottom : Sizing.pctH(2) + readonly property int rowSpacing: root.layoutProfile ? root.layoutProfile.listRowSpacing : Sizing.pctH(0.7) + readonly property int contentHeight: Math.max(0, height - cardPaddingTop - cardPaddingBottom) + readonly property int rowHeight: root.layoutProfile && root.layoutProfile.listRowHeight > 0 ? root.layoutProfile.listRowHeight : (targetVisibleRowCount > 0 ? Math.max(Sizing.pctH(3), Math.floor((contentHeight - (rowSpacing * (targetVisibleRowCount - 1))) / targetVisibleRowCount)) : Sizing.pctH(6)) readonly property int rowStride: rowHeight + rowSpacing readonly property int visibleRowCount: targetVisibleRowCount > 0 ? targetVisibleRowCount : Math.max(1, Math.floor((contentHeight + rowSpacing) / rowStride)) - readonly property int _centerSlot: Math.max(0, Math.floor((visibleRowCount - 1) / 2)) + readonly property int _centerSlot: root.layoutProfile && root.layoutProfile.listCenterSlot >= 0 ? Math.max(0, Math.min(visibleRowCount - 1, root.layoutProfile.listCenterSlot)) : Math.max(0, Math.floor((visibleRowCount - 1) / 2)) readonly property int _maxViewTopIndex: Math.max(0, itemCount - visibleRowCount) readonly property int _viewTopIndex: Math.max(0, Math.min(_maxViewTopIndex, currentIndex - _centerSlot)) readonly property int _targetContentY: _viewTopIndex * rowStride readonly property int _maxScrollTopIndex: Math.max(0, totalItems - visibleRowCount) - readonly property int _gutterWidth: Sizing.pctW(3) - readonly property int _gutterGap: Sizing.pctW(1.5) + readonly property int _gutterWidth: root.layoutProfile ? root.layoutProfile.gridGutterWidth : Sizing.pctW(3) + readonly property int _gutterGap: root.layoutProfile && root.layoutProfile.listScrollbarGap !== undefined ? root.layoutProfile.listScrollbarGap : (root.layoutProfile ? root.layoutProfile.gridGutterGap : Sizing.pctW(1.5)) + readonly property int _scrollThumbWidth: root.layoutProfile ? root.layoutProfile.scrollThumbWidth : Sizing.pctW(1.2) + readonly property int _scrollThumbRightInset: root.layoutProfile ? root.layoutProfile.scrollThumbRightInset : 0 + readonly property int _scrollArrowSize: root.layoutProfile ? root.layoutProfile.scrollArrowSize : Math.min(root._gutterWidth, Sizing.pctH(4)) + readonly property int _selectionAccentWidth: root.layoutProfile && root.layoutProfile.listSelectionAccentWidth !== undefined ? root.layoutProfile.listSelectionAccentWidth : Sizing.pctW(0.45) + readonly property int _rowTextLeftPadding: root.layoutProfile ? root.layoutProfile.listRowTextLeftPadding : Sizing.pctW(1.6) + readonly property int _rowTextRightPadding: root.layoutProfile ? root.layoutProfile.listRowTextRightPadding : Sizing.pctW(1.6) + readonly property int _favoriteRightPadding: root.layoutProfile ? root.layoutProfile.listFavoriteRightPadding : Sizing.pctW(1.6) signal itemHovered(int index) signal itemClicked(int index) @@ -87,13 +98,13 @@ Item { id: listView anchors.left: parent.left - anchors.leftMargin: root.cardPaddingX + anchors.leftMargin: root.cardPaddingLeft anchors.top: parent.top - anchors.topMargin: root.cardPaddingY + anchors.topMargin: root.cardPaddingTop anchors.bottom: parent.bottom - anchors.bottomMargin: root.cardPaddingY + anchors.bottomMargin: root.cardPaddingBottom anchors.right: parent.right - anchors.rightMargin: root.totalItems > root.visibleRowCount ? root._gutterWidth + root._gutterGap + root.cardPaddingX : root.cardPaddingX + anchors.rightMargin: root.totalItems > root.visibleRowCount ? root._gutterWidth + root._gutterGap + root.cardPaddingRight : root.cardPaddingRight model: root.model currentIndex: root.currentIndex contentY: Math.min(root._targetContentY, Math.max(0, contentHeight - height)) @@ -139,14 +150,14 @@ Item { Rectangle { anchors.fill: parent color: Theme.selectionSurface - radius: Sizing.cornerRadius + radius: root._selectionRadius } Rectangle { anchors.left: parent.left anchors.top: parent.top anchors.bottom: parent.bottom - width: Sizing.cornerRadius + width: root._selectionRadius color: Theme.selectionSurface } } @@ -155,7 +166,7 @@ Item { anchors.left: parent.left anchors.top: parent.top anchors.bottom: parent.bottom - width: Sizing.pctW(0.45) + width: root._selectionAccentWidth color: Theme.accent visible: row.selected radius: Math.max(0, Sizing.px(width / 3)) @@ -163,9 +174,9 @@ Item { Text { anchors.left: parent.left - anchors.leftMargin: Sizing.pctW(1.6) + anchors.leftMargin: root._rowTextLeftPadding anchors.right: parent.right - anchors.rightMargin: row.favorite !== 0 ? Sizing.pctW(5.2) : Sizing.pctW(1.6) + anchors.rightMargin: row.favorite !== 0 ? root._favoriteRightPadding + Sizing.pctH(3.2) + root._rowTextRightPadding : root._rowTextRightPadding anchors.verticalCenter: parent.verticalCenter text: root.showFileStem && row.fileStem !== "" ? row.fileStem : row.name color: row.selected ? Theme.textPrimary : Theme.textLabel @@ -178,7 +189,7 @@ Item { Image { anchors.right: parent.right - anchors.rightMargin: Sizing.pctW(1.6) + anchors.rightMargin: root._favoriteRightPadding anchors.verticalCenter: parent.verticalCenter width: Sizing.pctH(3.2) height: width @@ -214,21 +225,19 @@ Item { id: scrollGutter anchors.right: parent.right - anchors.rightMargin: root.cardPaddingX + anchors.rightMargin: root.cardPaddingRight anchors.top: parent.top - anchors.topMargin: root.cardPaddingY + anchors.topMargin: root.cardPaddingTop anchors.bottom: parent.bottom - anchors.bottomMargin: root.cardPaddingY + anchors.bottomMargin: root.cardPaddingBottom width: root._gutterWidth visible: root.totalItems > root.visibleRowCount - readonly property int arrowSize: Math.min(width, Sizing.pctH(4)) - Image { id: upArrow source: Resources.iconUrl("ScrollUp") - width: scrollGutter.arrowSize - height: scrollGutter.arrowSize + width: root._scrollArrowSize + height: root._scrollArrowSize anchors.top: parent.top anchors.horizontalCenter: parent.horizontalCenter fillMode: Image.PreserveAspectFit @@ -247,8 +256,8 @@ Item { Image { id: downArrow source: Resources.iconUrl("ScrollDown") - width: scrollGutter.arrowSize - height: scrollGutter.arrowSize + width: root._scrollArrowSize + height: root._scrollArrowSize anchors.bottom: parent.bottom anchors.horizontalCenter: parent.horizontalCenter fillMode: Image.PreserveAspectFit @@ -267,10 +276,12 @@ Item { Item { id: scrollRegion anchors.top: parent.top - anchors.topMargin: scrollGutter.arrowSize + Sizing.pctH(1) + anchors.topMargin: root._scrollArrowSize + Sizing.pctH(1) anchors.bottom: parent.bottom - anchors.bottomMargin: scrollGutter.arrowSize + Sizing.pctH(1) - anchors.horizontalCenter: parent.horizontalCenter + anchors.bottomMargin: root._scrollArrowSize + Sizing.pctH(1) + anchors.right: parent.right + anchors.rightMargin: root._scrollThumbRightInset + width: root._scrollThumbWidth readonly property int _minThumbHeight: Sizing.pctH(4) readonly property int _thumbHeight: root.totalItems <= 0 ? 0 : Math.min(scrollRegion.height, Math.max(_minThumbHeight, Math.round(scrollRegion.height * root.visibleRowCount / root.totalItems))) @@ -278,9 +289,9 @@ Item { Rectangle { id: scrollThumb - width: Sizing.pctW(1.2) + width: root._scrollThumbWidth height: scrollRegion._thumbHeight - anchors.horizontalCenter: parent.horizontalCenter + anchors.right: parent.right y: scrollRegion._thumbY color: Theme.textPrimary radius: Sizing.half(width) diff --git a/src/ui/components/BrowseListDetailView.qml b/src/ui/components/BrowseListDetailView.qml index 1a38c87..0dbe1f6 100644 --- a/src/ui/components/BrowseListDetailView.qml +++ b/src/ui/components/BrowseListDetailView.qml @@ -17,6 +17,7 @@ Item { property alias currentCoverKey: browseList.currentCoverKey property alias itemCount: browseList.itemCount property alias visibleRowCount: browseList.visibleRowCount + property var layoutProfile: null property alias detailTitle: detailPane.title property alias detailCoverKey: detailPane.coverKey @@ -29,6 +30,8 @@ Item { property alias detailSuppressed: detailPane.detailSuppressed property alias detailCanPreviousImage: detailPane.canPreviousImage property alias detailCanNextImage: detailPane.canNextImage + readonly property int _cardRadius: root.layoutProfile ? root.layoutProfile.tileCornerRadius : Sizing.cornerRadius + readonly property int _dividerOffsetX: root.layoutProfile && root.layoutProfile.listDividerOffsetX !== undefined ? root.layoutProfile.listDividerOffsetX : 0 signal itemHovered(int index) signal itemClicked(int index) @@ -45,13 +48,13 @@ Item { color: Theme.surfaceCard border.width: Sizing.stroke(1) border.color: Theme.borderMid - radius: Sizing.cornerRadius + radius: root._cardRadius } CardDivider { id: listDivider - x: Sizing.px(parent.width * 2 / 3) + x: Sizing.px(parent.width * 2 / 3) + root._dividerOffsetX anchors.top: parent.top anchors.bottom: parent.bottom } @@ -63,6 +66,7 @@ Item { anchors.right: listDivider.left anchors.top: parent.top anchors.bottom: parent.bottom + layoutProfile: root.layoutProfile showChrome: false onItemHovered: index => root.itemHovered(index) onItemClicked: index => root.itemClicked(index) @@ -78,6 +82,7 @@ Item { anchors.right: parent.right anchors.top: parent.top anchors.bottom: parent.bottom + layoutProfile: root.layoutProfile showChrome: false } } diff --git a/src/ui/components/HeaderBar.qml b/src/ui/components/HeaderBar.qml index 781fe10..60db43b 100644 --- a/src/ui/components/HeaderBar.qml +++ b/src/ui/components/HeaderBar.qml @@ -26,6 +26,7 @@ Item { property alias logoItem: logo property var layoutProfile: null property string browseTitle: "" + property string browseProgressText: "" height: Sizing.headerHeight @@ -44,6 +45,25 @@ Item { source: "qrc:/qt/qml/Zaparoo/App/resources/images/logo.png" } + Text { + id: browseProgressLabel + + visible: header.browseProgressText !== "" + anchors.left: logo.right + anchors.leftMargin: Sizing.pctW(1) + anchors.verticalCenter: logo.verticalCenter + width: Math.max(0, Math.floor(parent.width / 4)) + height: Sizing.headerRowHeight + elide: Text.ElideRight + horizontalAlignment: Text.AlignLeft + verticalAlignment: Text.AlignVCenter + text: header.browseProgressText + font.family: Theme.fontUi + font.pixelSize: Sizing.fontSize(2.9) + color: Theme.textPrimary + renderType: Text.NativeRendering + } + TextMetrics { id: clockMetrics diff --git a/src/ui/components/TopStatusStrip.qml b/src/ui/components/TopStatusStrip.qml index 652a183..ec19150 100644 --- a/src/ui/components/TopStatusStrip.qml +++ b/src/ui/components/TopStatusStrip.qml @@ -24,8 +24,8 @@ Item { property int totalPages: 1 property string totalText: "" // formatted; empty hides the slot property string rightTextOverride: "" // formatted; non-empty replaces Page N / M + property int slotMargin: Sizing.pctW(5) readonly property int _slotWidth: Sizing.px(status.width / 3) - readonly property int _slotMargin: Sizing.pctW(5) readonly property int _textMeasureSlack: Theme.crtNativePath ? 0 : 2 readonly property int _titleMeasuredWidth: Math.ceil(Math.max(titleMetrics.advanceWidth, titleMetrics.boundingRect.width) + status._textMeasureSlack) readonly property int _titleTextWidth: Math.min(status._slotWidth, status._titleMeasuredWidth) @@ -40,9 +40,9 @@ Item { visible: status.totalText !== "" anchors.left: parent.left - anchors.leftMargin: status._slotMargin + anchors.leftMargin: status.slotMargin anchors.bottom: titleText.bottom - width: status._slotWidth - status._slotMargin + width: status._slotWidth - status.slotMargin elide: Text.ElideRight horizontalAlignment: Text.AlignLeft text: status.totalText @@ -83,9 +83,9 @@ Item { visible: status.rightTextOverride !== "" || status.totalPages > 1 anchors.right: parent.right - anchors.rightMargin: status._slotMargin + anchors.rightMargin: status.slotMargin anchors.bottom: titleText.bottom - width: status._slotWidth - status._slotMargin + width: status._slotWidth - status.slotMargin elide: Text.ElideRight horizontalAlignment: Text.AlignRight text: status.rightTextOverride !== "" ? status.rightTextOverride : qsTr("Page %1 / %2").arg(status.currentPage + 1).arg(status.totalPages) diff --git a/src/ui/screens/FavoritesScreen.qml b/src/ui/screens/FavoritesScreen.qml index d2e2316..9d5033c 100644 --- a/src/ui/screens/FavoritesScreen.qml +++ b/src/ui/screens/FavoritesScreen.qml @@ -24,4 +24,5 @@ MediaListScreen { screenTitle: qsTr("Favorites") emptyText: qsTr("No favorites yet") loadingText: qsTr("Loading favorites…") + detailShowTitle: false } diff --git a/src/ui/screens/MediaListScreen.qml b/src/ui/screens/MediaListScreen.qml index 93625c4..4144855 100644 --- a/src/ui/screens/MediaListScreen.qml +++ b/src/ui/screens/MediaListScreen.qml @@ -84,6 +84,8 @@ Item { property int gridTotalItemsOverride: -1 property bool gridHasMorePages: false readonly property bool _listLayout: root.forceListLayout || Browse.Settings.current_browse_layout === "list" + readonly property bool _crtListStrip: Theme.crtNativePath && root._listLayout + readonly property var _listLayoutProfile: Theme.crtNativePath ? BrowseLayouts.crtTile : BrowseLayouts.defaultTile readonly property int _listOverlayBottomMargin: Sizing.pctH(15) readonly property bool _gateHide: root.transitioning || root._loading() @@ -283,12 +285,13 @@ Item { TopStatusStrip { id: topStrip - visible: !root._gateHide && root.showTopStrip + visible: !root._gateHide && (root.showTopStrip || root._crtListStrip) anchors.left: parent.left anchors.right: parent.right anchors.top: parent.top anchors.topMargin: Sizing.headerBottom + Sizing.pctH(1) - height: root.showTopStrip ? Sizing.pctH(7) : 0 + height: root._crtListStrip ? root._listLayoutProfile.listStripHeight : (root.showTopStrip ? Sizing.pctH(7) : 0) + slotMargin: root._crtListStrip ? root._listLayoutProfile.listStripSlotMargin : Sizing.pctW(5) title: typeof root.topStripTitleProvider === "function" ? root.topStripTitleProvider() : root.screenTitle currentPage: typeof root.topStripCurrentPageProvider === "function" ? root.topStripCurrentPageProvider() : mediaGrid.currentPage totalPages: typeof root.topStripTotalPagesProvider === "function" ? root.topStripTotalPagesProvider() : Math.max(1, Math.ceil(root._count() / mediaGrid.pageSize)) @@ -301,13 +304,14 @@ Item { visible: !root._gateHide && root._listLayout anchors.left: parent.left - anchors.leftMargin: Sizing.pctW(5) + anchors.leftMargin: root._listLayoutProfile.listCardSideMargin anchors.right: parent.right - anchors.rightMargin: Sizing.pctW(5) + anchors.rightMargin: root._listLayoutProfile.listCardSideMargin anchors.top: topStrip.bottom anchors.topMargin: Sizing.pctH(2) anchors.bottom: parent.bottom anchors.bottomMargin: Sizing.pctH(8) + layoutProfile: root._listLayoutProfile model: root.mediaModel totalItemsOverride: root.totalItemsOverride targetVisibleRowCount: root.targetVisibleRowCount diff --git a/src/ui/screens/RecentsScreen.qml b/src/ui/screens/RecentsScreen.qml index 8301ac3..db1fe13 100644 --- a/src/ui/screens/RecentsScreen.qml +++ b/src/ui/screens/RecentsScreen.qml @@ -24,4 +24,5 @@ MediaListScreen { screenTitle: qsTr("Recently Played") emptyText: qsTr("Nothing played yet") loadingText: qsTr("Loading recently played…") + detailShowTitle: false } diff --git a/src/ui/screens/SystemsScreen.qml b/src/ui/screens/SystemsScreen.qml index e95ff3e..7f3f66c 100644 --- a/src/ui/screens/SystemsScreen.qml +++ b/src/ui/screens/SystemsScreen.qml @@ -38,7 +38,8 @@ Item { property bool gridFocused: true readonly property bool _listLayout: Browse.Settings.current_browse_layout === "list" readonly property bool _crtGridLayout: Theme.crtNativePath && !systems._listLayout - readonly property var _tileLayout: systems._crtGridLayout ? BrowseLayouts.crtTile : BrowseLayouts.defaultTile + readonly property bool _crtListStrip: Theme.crtNativePath && systems._listLayout + readonly property var _tileLayout: Theme.crtNativePath ? BrowseLayouts.crtTile : BrowseLayouts.defaultTile readonly property int _listOverlayBottomMargin: Sizing.pctH(6) + systems._tileLayout.activeLabelBottomMargin + systems._tileLayout.activeLabelHeight signal requestAccept(systemId: string) @@ -178,17 +179,14 @@ Item { anchors.right: parent.right anchors.top: parent.top anchors.topMargin: Sizing.headerBottom + Sizing.pctH(1) - height: systems._tileLayout.showTopStrip ? Sizing.pctH(7) : 0 + height: systems._crtListStrip ? systems._tileLayout.listStripHeight : (systems._tileLayout.showTopStrip ? Sizing.pctH(7) : 0) + slotMargin: systems._crtListStrip ? systems._tileLayout.listStripSlotMargin : Sizing.pctW(5) title: systems._tileLayout.showHeaderTitleInHeader ? "" : Browse.SystemsModel.current_category currentPage: systemsGrid.currentPage totalPages: systems._tileLayout.showBottomStatusRow ? 1 : Math.max(1, Math.ceil(Browse.SystemsModel.count / systemsGrid.pageSize)) - totalText: systems._listLayout || systems._tileLayout.showBottomStatusRow ? "" : (Browse.SystemsModel.count > 0 ? qsTr("%1 systems").arg(Browse.SystemsModel.count) : "") - rightTextOverride: { - if (!systems._listLayout || systemsGrid.itemCount <= 0) - return ""; - return qsTr("%1 / %2").arg(systemsGrid.currentIndex + 1).arg(Math.max(1, Browse.SystemsModel.count)); - } - visible: !systems.transitioning && systems._tileLayout.showTopStrip + totalText: Theme.crtNativePath ? "" : (Browse.SystemsModel.count > 0 ? qsTr("%1 systems").arg(Browse.SystemsModel.count) : "") + rightTextOverride: !systems._listLayout || systemsGrid.itemCount <= 0 ? "" : qsTr("%1 / %2").arg(systemsGrid.currentIndex + 1).arg(Math.max(1, Browse.SystemsModel.count)) + visible: !systems.transitioning && (systems._tileLayout.showTopStrip || systems._crtListStrip) } BrowseListDetailView { @@ -196,9 +194,9 @@ Item { visible: !systems.transitioning && systems._listLayout anchors.left: parent.left - anchors.leftMargin: Sizing.pctW(5) + anchors.leftMargin: systems._tileLayout.listCardSideMargin anchors.right: parent.right - anchors.rightMargin: Sizing.pctW(5) + anchors.rightMargin: systems._tileLayout.listCardSideMargin anchors.top: topStrip.bottom anchors.topMargin: Sizing.pctH(2) anchors.bottom: parent.bottom diff --git a/src/ui/theme/BrowseLayouts.qml b/src/ui/theme/BrowseLayouts.qml index 3b13943..2720447 100644 --- a/src/ui/theme/BrowseLayouts.qml +++ b/src/ui/theme/BrowseLayouts.qml @@ -32,6 +32,38 @@ QtObject { readonly property int bottomStatusRightMargin: Sizing.pctW(5) readonly property int bottomUnsafeHeight: Sizing.pctH(6) + Sizing.pctH(2) readonly property int tileCornerRadius: Sizing.cornerRadius + readonly property int listCardSideMargin: Sizing.pctW(5) + readonly property int listDividerOffsetX: 0 + readonly property int listStripHeight: Sizing.pctH(7) + readonly property int listStripSlotMargin: Sizing.pctW(5) + readonly property int listCardPaddingLeft: Sizing.pctW(2) + readonly property int listCardPaddingRight: Sizing.pctW(2) + readonly property int listCardPaddingTop: Sizing.pctH(2) + readonly property int listCardPaddingBottom: Sizing.pctH(2) + readonly property int listRowHeight: 0 + readonly property int listRowSpacing: Sizing.pctH(0.7) + readonly property int listCenterSlot: -1 + readonly property int listScrollbarGap: Sizing.pctW(1.5) + readonly property int listSelectionAccentWidth: Sizing.pctW(0.45) + readonly property int detailMetadataYOffset: 0 + readonly property int detailMetadataExtraHeight: 0 + readonly property int detailMetadataLeftInset: 0 + readonly property int detailMetadataRightInset: 0 + readonly property int detailPanePaddingLeft: Sizing.pctW(2) + readonly property int detailPanePaddingRight: Sizing.pctW(2) + readonly property int detailPanePaddingTop: Sizing.pctH(2) + readonly property int detailPanePaddingBottom: Sizing.pctH(2) + readonly property int detailImageXOffset: 0 + readonly property int detailImageLeftInset: 0 + readonly property int detailImageRightInset: 0 + readonly property int detailImageExtraWidth: 0 + readonly property int detailImageExtraHeight: 0 + readonly property int detailImageBottomGap: 0 + readonly property int detailTagRowHeight: Sizing.pctH(3) + readonly property int detailTagRowSpacing: Sizing.pctH(0.55) + readonly property int listRowTextLeftPadding: Sizing.pctW(1.6) + readonly property int listRowTextRightPadding: Sizing.pctW(1.6) + readonly property int listFavoriteRightPadding: Sizing.pctW(1.6) } readonly property QtObject crtTile: QtObject { @@ -53,10 +85,42 @@ QtObject { readonly property int scrollArrowSize: 8 readonly property bool packHorizontalRemainderAfterGutter: true readonly property int activeLabelHeight: 8 - readonly property int activeLabelBottomMargin: Sizing.pctH(6) + 4 + readonly property int activeLabelBottomMargin: Sizing.pctH(6) readonly property int bottomStatusLeftMargin: 4 readonly property int bottomStatusRightMargin: Sizing.pctW(5) readonly property int bottomUnsafeHeight: 16 readonly property int tileCornerRadius: 4 + readonly property int listCardSideMargin: 4 + readonly property int listDividerOffsetX: -16 + readonly property int listStripHeight: 8 + readonly property int listStripSlotMargin: Sizing.headerSideMargin + readonly property int listCardPaddingLeft: 3 + readonly property int listCardPaddingRight: 2 + readonly property int listCardPaddingTop: 3 + readonly property int listCardPaddingBottom: 2 + readonly property int listRowHeight: 12 + readonly property int listRowSpacing: 0 + readonly property int listCenterSlot: 7 + readonly property int listScrollbarGap: 2 + readonly property int listSelectionAccentWidth: 2 + readonly property int detailMetadataYOffset: -14 + readonly property int detailMetadataExtraHeight: 2 + readonly property int detailMetadataLeftInset: 2 + readonly property int detailMetadataRightInset: 1 + readonly property int detailPanePaddingLeft: 1 + readonly property int detailPanePaddingRight: 1 + readonly property int detailPanePaddingTop: 3 + readonly property int detailPanePaddingBottom: 2 + readonly property int detailImageXOffset: 0 + readonly property int detailImageLeftInset: 2 + readonly property int detailImageRightInset: 2 + readonly property int detailImageExtraWidth: 16 + readonly property int detailImageExtraHeight: 0 + readonly property int detailImageBottomGap: 2 + readonly property int detailTagRowHeight: 9 + readonly property int detailTagRowSpacing: 0 + readonly property int listRowTextLeftPadding: 4 + readonly property int listRowTextRightPadding: 2 + readonly property int listFavoriteRightPadding: 2 } } From 92c1bdc4dda8ce6a0c60ec32abbd7e6aa08c6a65 Mon Sep 17 00:00:00 2001 From: Andrea Bogazzi Date: Mon, 25 May 2026 01:07:23 +0200 Subject: [PATCH 2/4] progress --- scripts/run-macos-mister-core.sh | 2 +- src/ui/components/BrowseList.qml | 9 ++++++--- src/ui/components/PagedGrid.qml | 9 ++++++--- src/ui/theme/BrowseLayouts.qml | 2 ++ 4 files changed, 15 insertions(+), 7 deletions(-) diff --git a/scripts/run-macos-mister-core.sh b/scripts/run-macos-mister-core.sh index 01d38be..c227472 100755 --- a/scripts/run-macos-mister-core.sh +++ b/scripts/run-macos-mister-core.sh @@ -17,5 +17,5 @@ fi export ZAPAROO_CORE_ENDPOINT="ws://192.168.1.176:7497/api/v0.1" export ZAPAROO_CRT_PREVIEW_SCALE=3 -exec "${FRONTEND}" --crt +exec "${FRONTEND}" # exec "${FRONTEND}" --crt diff --git a/src/ui/components/BrowseList.qml b/src/ui/components/BrowseList.qml index 9d72ac9..26f7177 100644 --- a/src/ui/components/BrowseList.qml +++ b/src/ui/components/BrowseList.qml @@ -39,6 +39,7 @@ Item { readonly property int _gutterGap: root.layoutProfile && root.layoutProfile.listScrollbarGap !== undefined ? root.layoutProfile.listScrollbarGap : (root.layoutProfile ? root.layoutProfile.gridGutterGap : Sizing.pctW(1.5)) readonly property int _scrollThumbWidth: root.layoutProfile ? root.layoutProfile.scrollThumbWidth : Sizing.pctW(1.2) readonly property int _scrollThumbRightInset: root.layoutProfile ? root.layoutProfile.scrollThumbRightInset : 0 + readonly property bool _scrollThumbRightAligned: root.layoutProfile && root.layoutProfile.scrollThumbRightAligned !== undefined ? root.layoutProfile.scrollThumbRightAligned : false readonly property int _scrollArrowSize: root.layoutProfile ? root.layoutProfile.scrollArrowSize : Math.min(root._gutterWidth, Sizing.pctH(4)) readonly property int _selectionAccentWidth: root.layoutProfile && root.layoutProfile.listSelectionAccentWidth !== undefined ? root.layoutProfile.listSelectionAccentWidth : Sizing.pctW(0.45) readonly property int _rowTextLeftPadding: root.layoutProfile ? root.layoutProfile.listRowTextLeftPadding : Sizing.pctW(1.6) @@ -279,8 +280,9 @@ Item { anchors.topMargin: root._scrollArrowSize + Sizing.pctH(1) anchors.bottom: parent.bottom anchors.bottomMargin: root._scrollArrowSize + Sizing.pctH(1) - anchors.right: parent.right - anchors.rightMargin: root._scrollThumbRightInset + anchors.right: root._scrollThumbRightAligned ? parent.right : undefined + anchors.rightMargin: root._scrollThumbRightAligned ? root._scrollThumbRightInset : 0 + anchors.horizontalCenter: root._scrollThumbRightAligned ? undefined : parent.horizontalCenter width: root._scrollThumbWidth readonly property int _minThumbHeight: Sizing.pctH(4) @@ -291,7 +293,8 @@ Item { id: scrollThumb width: root._scrollThumbWidth height: scrollRegion._thumbHeight - anchors.right: parent.right + anchors.right: root._scrollThumbRightAligned ? parent.right : undefined + anchors.horizontalCenter: root._scrollThumbRightAligned ? undefined : parent.horizontalCenter y: scrollRegion._thumbY color: Theme.textPrimary radius: Sizing.half(width) diff --git a/src/ui/components/PagedGrid.qml b/src/ui/components/PagedGrid.qml index 61eced9..96ec69f 100644 --- a/src/ui/components/PagedGrid.qml +++ b/src/ui/components/PagedGrid.qml @@ -170,6 +170,7 @@ Item { readonly property int gutterGap: root.layoutProfile ? root.layoutProfile.gridGutterGap : Sizing.pctW(1.5) readonly property int scrollThumbWidth: root.layoutProfile ? root.layoutProfile.scrollThumbWidth : Sizing.pctW(1.2) readonly property int scrollThumbRightInset: root.layoutProfile ? root.layoutProfile.scrollThumbRightInset : 0 + readonly property bool scrollThumbRightAligned: root.layoutProfile && root.layoutProfile.scrollThumbRightAligned !== undefined ? root.layoutProfile.scrollThumbRightAligned : false readonly property int scrollArrowSize: root.layoutProfile ? root.layoutProfile.scrollArrowSize : Math.min(gutterWidth, Sizing.pctH(4)) readonly property int topInset: root.layoutProfile ? root.layoutProfile.gridTopInset : Sizing.pctH(2) readonly property int bottomInset: root.layoutProfile ? root.layoutProfile.gridBottomInset : Sizing.pctH(2) @@ -717,8 +718,9 @@ Item { anchors.topMargin: root.scrollArrowSize + Sizing.pctH(1) anchors.bottom: parent.bottom anchors.bottomMargin: root.scrollArrowSize + Sizing.pctH(1) - anchors.right: parent.right - anchors.rightMargin: root.scrollThumbRightInset + anchors.right: root.scrollThumbRightAligned ? parent.right : undefined + anchors.rightMargin: root.scrollThumbRightAligned ? root.scrollThumbRightInset : 0 + anchors.horizontalCenter: root.scrollThumbRightAligned ? undefined : parent.horizontalCenter width: root.scrollThumbWidth // Standard paginated-scrollbar formulas (cf. Qt @@ -735,7 +737,8 @@ Item { id: scrollThumb width: root.scrollThumbWidth height: scrollRegion._thumbHeight - anchors.right: parent.right + anchors.right: root.scrollThumbRightAligned ? parent.right : undefined + anchors.horizontalCenter: root.scrollThumbRightAligned ? undefined : parent.horizontalCenter y: scrollRegion._thumbY color: Theme.textPrimary radius: Sizing.half(width) diff --git a/src/ui/theme/BrowseLayouts.qml b/src/ui/theme/BrowseLayouts.qml index 2720447..4b96161 100644 --- a/src/ui/theme/BrowseLayouts.qml +++ b/src/ui/theme/BrowseLayouts.qml @@ -24,6 +24,7 @@ QtObject { readonly property int gridRowGap: Sizing.pctH(4) readonly property int scrollThumbWidth: Sizing.pctW(1.2) readonly property int scrollThumbRightInset: 0 + readonly property bool scrollThumbRightAligned: false readonly property int scrollArrowSize: Math.min(gridGutterWidth, Sizing.pctH(4)) readonly property bool packHorizontalRemainderAfterGutter: false readonly property int activeLabelHeight: Sizing.pctH(7) @@ -82,6 +83,7 @@ QtObject { readonly property int gridRowGap: 4 readonly property int scrollThumbWidth: 4 readonly property int scrollThumbRightInset: 2 + readonly property bool scrollThumbRightAligned: false readonly property int scrollArrowSize: 8 readonly property bool packHorizontalRemainderAfterGutter: true readonly property int activeLabelHeight: 8 From 6df5a7f25f9e482d436268b2b2cdaddb98d292e6 Mon Sep 17 00:00:00 2001 From: Andrea Bogazzi Date: Mon, 25 May 2026 08:31:38 +0200 Subject: [PATCH 3/4] ok nice --- scripts/run-macos-mister-core.sh | 2 +- src/ui/screens/GamesScreen.qml | 2 +- src/ui/screens/SystemsScreen.qml | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/run-macos-mister-core.sh b/scripts/run-macos-mister-core.sh index c227472..01d38be 100755 --- a/scripts/run-macos-mister-core.sh +++ b/scripts/run-macos-mister-core.sh @@ -17,5 +17,5 @@ fi export ZAPAROO_CORE_ENDPOINT="ws://192.168.1.176:7497/api/v0.1" export ZAPAROO_CRT_PREVIEW_SCALE=3 -exec "${FRONTEND}" +exec "${FRONTEND}" --crt # exec "${FRONTEND}" --crt diff --git a/src/ui/screens/GamesScreen.qml b/src/ui/screens/GamesScreen.qml index 01049e3..88b6274 100644 --- a/src/ui/screens/GamesScreen.qml +++ b/src/ui/screens/GamesScreen.qml @@ -118,7 +118,7 @@ MediaListScreen { return qsTr("%1 / %2").arg(games.gamesGrid.currentIndex + 1).arg(total); } gridLayoutProfile: games._tileLayout - gridBottomMargin: Sizing.pctH(6) + games._tileLayout.activeLabelBottomMargin + games._tileLayout.activeLabelHeight + gridBottomMargin: games._tileLayout.showBottomStatusRow ? games._tileLayout.activeLabelBottomMargin + games._tileLayout.activeLabelHeight : Sizing.pctH(6) + games._tileLayout.activeLabelBottomMargin + games._tileLayout.activeLabelHeight gridTotalItemsOverride: Browse.GamesModel.dir_count + Browse.GamesModel.total_files gridHasMorePages: Browse.GamesModel.has_next_page gridLoadMoreAction: () => Browse.GamesModel.fetch_more() diff --git a/src/ui/screens/SystemsScreen.qml b/src/ui/screens/SystemsScreen.qml index 7f3f66c..97c45bf 100644 --- a/src/ui/screens/SystemsScreen.qml +++ b/src/ui/screens/SystemsScreen.qml @@ -230,7 +230,7 @@ Item { anchors.right: parent.right anchors.top: topStrip.bottom anchors.bottom: parent.bottom - anchors.bottomMargin: Sizing.pctH(6) + systems._tileLayout.activeLabelBottomMargin + systems._tileLayout.activeLabelHeight + anchors.bottomMargin: systems._tileLayout.showBottomStatusRow ? systems._tileLayout.activeLabelBottomMargin + systems._tileLayout.activeLabelHeight : Sizing.pctH(6) + systems._tileLayout.activeLabelBottomMargin + systems._tileLayout.activeLabelHeight focused: systems.gridFocused model: Browse.SystemsModel layoutProfile: systems._tileLayout @@ -271,7 +271,7 @@ Item { } Text { - visible: systems._tileLayout.showBottomStatusRow && !systems.transitioning && Browse.SystemsModel.count > 0 + visible: systems._tileLayout.showBottomStatusRow && !systems.transitioning && !systems._listLayout && Browse.SystemsModel.count > 0 anchors.left: parent.left anchors.leftMargin: systems._tileLayout.bottomStatusLeftMargin anchors.verticalCenter: activeLabel.verticalCenter @@ -288,7 +288,7 @@ Item { } Text { - visible: systems._tileLayout.showBottomStatusRow && !systems.transitioning && Math.ceil(Browse.SystemsModel.count / systemsGrid.pageSize) > 1 + visible: systems._tileLayout.showBottomStatusRow && !systems.transitioning && !systems._listLayout && Math.ceil(Browse.SystemsModel.count / systemsGrid.pageSize) > 1 anchors.right: parent.right anchors.rightMargin: systems._tileLayout.bottomStatusRightMargin anchors.verticalCenter: activeLabel.verticalCenter From 0eb90016c6c2b912b2b668e3fa39de92d15db728 Mon Sep 17 00:00:00 2001 From: Andrea Bogazzi Date: Mon, 25 May 2026 09:28:27 +0200 Subject: [PATCH 4/4] fix test --- tests/ui/tst_browse_layout_profiles.qml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/ui/tst_browse_layout_profiles.qml b/tests/ui/tst_browse_layout_profiles.qml index d010460..96be6e5 100644 --- a/tests/ui/tst_browse_layout_profiles.qml +++ b/tests/ui/tst_browse_layout_profiles.qml @@ -52,13 +52,13 @@ TestCase { compare(main.systemsScreen.systemsGrid.scrollArrowSize, 8); } - function test_list_mode_uses_default_tile_profile(): void { + function test_crt_list_uses_crt_header_and_profile(): void { main.crtNativePath = true; Browse.Settings.current_browse_layout = "list"; - compare(main.headerBar.layoutProfile.showHeaderTitleInHeader, false); - compare(main.systemsScreen.systemsGrid.layoutProfile.tileCornerRadius, Sizing.cornerRadius); - compare(main.systemsScreen.systemsGrid.leftInset, Sizing.pctW(5)); - compare(main.systemsScreen.systemsGrid.gutterWidth, Sizing.pctW(3)); + compare(main.headerBar.layoutProfile.showHeaderTitleInHeader, true); + compare(main.systemsScreen.systemsGrid.layoutProfile.tileCornerRadius, 4); + compare(main.systemsScreen.systemsGrid.leftInset, 4); + compare(main.systemsScreen.systemsGrid.gutterWidth, 8); } }