Bladeren bron

Align, resize, and layout everything uniformly in the unified search view

Signed-off-by: Claudio Cambra <claudio.cambra@gmail.com>
Claudio Cambra 3 jaren geleden
bovenliggende
commit
316f3981ab

+ 1 - 0
resources.qrc

@@ -23,6 +23,7 @@
         <file>src/gui/tray/UnifiedSearchResultItem.qml</file>
         <file>src/gui/tray/UnifiedSearchResultItem.qml</file>
         <file>src/gui/tray/UnifiedSearchResultItemSkeleton.qml</file>
         <file>src/gui/tray/UnifiedSearchResultItemSkeleton.qml</file>
         <file>src/gui/tray/UnifiedSearchResultItemSkeletonContainer.qml</file>
         <file>src/gui/tray/UnifiedSearchResultItemSkeletonContainer.qml</file>
+        <file>src/gui/tray/UnifiedSearchResultItemSkeletonGradientRectangle.qml</file>
         <file>src/gui/tray/UnifiedSearchResultListItem.qml</file>
         <file>src/gui/tray/UnifiedSearchResultListItem.qml</file>
         <file>src/gui/tray/UnifiedSearchResultNothingFound.qml</file>
         <file>src/gui/tray/UnifiedSearchResultNothingFound.qml</file>
         <file>src/gui/tray/UnifiedSearchResultSectionItem.qml</file>
         <file>src/gui/tray/UnifiedSearchResultSectionItem.qml</file>

+ 14 - 8
src/gui/tray/UnifiedSearchResultFetchMoreTrigger.qml

@@ -8,7 +8,6 @@ ColumnLayout {
     id: unifiedSearchResultItemFetchMore
     id: unifiedSearchResultItemFetchMore
 
 
     property bool isFetchMoreInProgress: false
     property bool isFetchMoreInProgress: false
-
     property bool isWithinViewPort: false
     property bool isWithinViewPort: false
 
 
     property int fontSize: Style.unifiedSearchResultTitleFontSize
     property int fontSize: Style.unifiedSearchResultTitleFontSize
@@ -21,22 +20,29 @@ ColumnLayout {
 
 
     Label {
     Label {
         id: unifiedSearchResultItemFetchMoreText
         id: unifiedSearchResultItemFetchMoreText
-        text: qsTr("Load more results")
-        visible: !unifiedSearchResultItemFetchMore.isFetchMoreInProgress
-        horizontalAlignment: Text.AlignHCenter
-        verticalAlignment: Text.AlignVCenter
+
         Layout.fillWidth: true
         Layout.fillWidth: true
         Layout.fillHeight: true
         Layout.fillHeight: true
+        Layout.leftMargin: Style.trayHorizontalMargin
+        Layout.rightMargin: Style.trayHorizontalMargin
+
+        horizontalAlignment: Text.AlignHCenter
+        verticalAlignment: Text.AlignVCenter
+        text: qsTr("Load more results")
+        wrapMode: Text.Wrap
         font.pixelSize: unifiedSearchResultItemFetchMore.fontSize
         font.pixelSize: unifiedSearchResultItemFetchMore.fontSize
         color: unifiedSearchResultItemFetchMore.textColor
         color: unifiedSearchResultItemFetchMore.textColor
+        visible: !unifiedSearchResultItemFetchMore.isFetchMoreInProgress
     }
     }
 
 
     BusyIndicator {
     BusyIndicator {
         id: unifiedSearchResultItemFetchMoreIconInProgress
         id: unifiedSearchResultItemFetchMoreIconInProgress
-        running: visible
-        visible: unifiedSearchResultItemFetchMore.isFetchMoreInProgress && unifiedSearchResultItemFetchMore.isWithinViewPort
-        Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
+
         Layout.preferredWidth: parent.height * 0.70
         Layout.preferredWidth: parent.height * 0.70
         Layout.preferredHeight: parent.height * 0.70
         Layout.preferredHeight: parent.height * 0.70
+        Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
+
+        running: visible
+        visible: unifiedSearchResultItemFetchMore.isFetchMoreInProgress && unifiedSearchResultItemFetchMore.isWithinViewPort
     }
     }
 }
 }

+ 38 - 38
src/gui/tray/UnifiedSearchResultItem.qml

@@ -2,9 +2,10 @@ import QtQml 2.15
 import QtQuick 2.9
 import QtQuick 2.9
 import QtQuick.Controls 2.3
 import QtQuick.Controls 2.3
 import QtQuick.Layouts 1.2
 import QtQuick.Layouts 1.2
-import Style 1.0
 import QtGraphicalEffects 1.0
 import QtGraphicalEffects 1.0
 
 
+import Style 1.0
+
 RowLayout {
 RowLayout {
     id: unifiedSearchResultItemDetails
     id: unifiedSearchResultItemDetails
 
 
@@ -12,14 +13,11 @@ RowLayout {
     property string subline: ""
     property string subline: ""
     property string icons: ""
     property string icons: ""
     property string iconPlaceholder: ""
     property string iconPlaceholder: ""
-    property bool isRounded: false
 
 
+    property bool iconsIsThumbnail: false
+    property bool isRounded: false
 
 
-    property int textLeftMargin: Style.unifiedSearchResultTextLeftMargin
-    property int textRightMargin: Style.unifiedSearchResultTextRightMargin
-    property int iconWidth: Style.unifiedSearchResultIconWidth
-    property int iconLeftMargin: Style.unifiedSearchResultIconLeftMargin
-
+    property int iconWidth: iconsIsThumbnail && icons !== "" ? Style.unifiedSearchResultIconWidth : Style.unifiedSearchResultSmallIconWidth
     property int titleFontSize: Style.unifiedSearchResultTitleFontSize
     property int titleFontSize: Style.unifiedSearchResultTitleFontSize
     property int sublineFontSize: Style.unifiedSearchResultSublineFontSize
     property int sublineFontSize: Style.unifiedSearchResultSublineFontSize
 
 
@@ -30,76 +28,78 @@ RowLayout {
     Accessible.name: resultTitle
     Accessible.name: resultTitle
     Accessible.onPressAction: unifiedSearchResultMouseArea.clicked()
     Accessible.onPressAction: unifiedSearchResultMouseArea.clicked()
 
 
-    ColumnLayout {
+    spacing: Style.trayHorizontalMargin
+
+    Item {
         id: unifiedSearchResultImageContainer
         id: unifiedSearchResultImageContainer
-        visible: true
-        Layout.preferredWidth: unifiedSearchResultItemDetails.iconWidth + 10
-        Layout.preferredHeight: unifiedSearchResultItemDetails.height
+
+        property int whiteSpace: (Style.trayListItemIconSize - unifiedSearchResultItemDetails.iconWidth)
+
+        Layout.preferredWidth: unifiedSearchResultItemDetails.iconWidth
+        Layout.preferredHeight: unifiedSearchResultItemDetails.iconWidth
+        Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
+        Layout.leftMargin: Style.trayHorizontalMargin + (whiteSpace * (0.5 - Style.thumbnailImageSizeReduction))
+        Layout.rightMargin: whiteSpace * (0.5 + Style.thumbnailImageSizeReduction)
+
         Image {
         Image {
             id: unifiedSearchResultThumbnail
             id: unifiedSearchResultThumbnail
+            anchors.fill: parent
             visible: false
             visible: false
             asynchronous: true
             asynchronous: true
-            source: "image://tray-image-provider/" + icons
+            source: "image://tray-image-provider/" + unifiedSearchResultItemDetails.icons
             cache: true
             cache: true
-            sourceSize.width: imageData.width
-            sourceSize.height: imageData.height
-            width: imageData.width
-            height: imageData.height
+            verticalAlignment: Qt.AlignVCenter
+            horizontalAlignment: Qt.AlignHCenter
+            sourceSize.width: width
+            sourceSize.height: height
         }
         }
         Rectangle {
         Rectangle {
             id: mask
             id: mask
+            anchors.fill: unifiedSearchResultThumbnail
             visible: false
             visible: false
-            radius: isRounded ? width / 2 : 0
-            width: imageData.width
-            height: imageData.height
+            radius: unifiedSearchResultItemDetails.isRounded ? width / 2 : 3
         }
         }
         OpacityMask {
         OpacityMask {
             id: imageData
             id: imageData
-            visible: !unifiedSearchResultThumbnailPlaceholder.visible && icons
-            Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
-            Layout.leftMargin: iconLeftMargin
-            Layout.preferredWidth: unifiedSearchResultItemDetails.iconWidth
-            Layout.preferredHeight: unifiedSearchResultItemDetails.iconWidth
+            anchors.fill: unifiedSearchResultThumbnail
+            visible: unifiedSearchResultItemDetails.icons !== ""
             source: unifiedSearchResultThumbnail
             source: unifiedSearchResultThumbnail
             maskSource: mask
             maskSource: mask
         }
         }
         Image {
         Image {
             id: unifiedSearchResultThumbnailPlaceholder
             id: unifiedSearchResultThumbnailPlaceholder
-            Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
-            Layout.leftMargin: iconLeftMargin
-            verticalAlignment: Qt.AlignCenter
+            anchors.fill: parent
+            verticalAlignment: Qt.AlignVCenter
+            horizontalAlignment: Qt.AlignHCenter
             cache: true
             cache: true
-            source: "image://tray-image-provider/" + iconPlaceholder
-            visible: false
+            source: "image://tray-image-provider/" + unifiedSearchResultItemDetails.iconPlaceholder
+            visible: unifiedSearchResultItemDetails.iconPlaceholder !== "" && unifiedSearchResultItemDetails.icons === ""
             sourceSize.height: unifiedSearchResultItemDetails.iconWidth
             sourceSize.height: unifiedSearchResultItemDetails.iconWidth
             sourceSize.width: unifiedSearchResultItemDetails.iconWidth
             sourceSize.width: unifiedSearchResultItemDetails.iconWidth
-            Layout.preferredWidth: unifiedSearchResultItemDetails.iconWidth
-            Layout.preferredHeight: unifiedSearchResultItemDetails.iconWidth
         }
         }
     }
     }
 
 
     ColumnLayout {
     ColumnLayout {
         id: unifiedSearchResultTextContainer
         id: unifiedSearchResultTextContainer
+
         Layout.fillWidth: true
         Layout.fillWidth: true
+        Layout.rightMargin: Style.trayHorizontalMargin
+        spacing: Style.standardSpacing
 
 
         Label {
         Label {
             id: unifiedSearchResultTitleText
             id: unifiedSearchResultTitleText
-            text: title.replace(/[\r\n]+/g, " ")
-            Layout.leftMargin: textLeftMargin
-            Layout.rightMargin: textRightMargin
             Layout.fillWidth: true
             Layout.fillWidth: true
+            text: unifiedSearchResultItemDetails.title.replace(/[\r\n]+/g, " ")
             elide: Text.ElideRight
             elide: Text.ElideRight
             font.pixelSize: unifiedSearchResultItemDetails.titleFontSize
             font.pixelSize: unifiedSearchResultItemDetails.titleFontSize
             color: unifiedSearchResultItemDetails.titleColor
             color: unifiedSearchResultItemDetails.titleColor
         }
         }
         Label {
         Label {
             id: unifiedSearchResultTextSubline
             id: unifiedSearchResultTextSubline
-            text: subline.replace(/[\r\n]+/g, " ")
+            Layout.fillWidth: true
+            text: unifiedSearchResultItemDetails.subline.replace(/[\r\n]+/g, " ")
             elide: Text.ElideRight
             elide: Text.ElideRight
             font.pixelSize: unifiedSearchResultItemDetails.sublineFontSize
             font.pixelSize: unifiedSearchResultItemDetails.sublineFontSize
-            Layout.leftMargin: textLeftMargin
-            Layout.rightMargin: textRightMargin
-            Layout.fillWidth: true
             color: unifiedSearchResultItemDetails.sublineColor
             color: unifiedSearchResultItemDetails.sublineColor
         }
         }
     }
     }

+ 18 - 50
src/gui/tray/UnifiedSearchResultItemSkeleton.qml

@@ -7,11 +7,7 @@ import Style 1.0
 RowLayout {
 RowLayout {
     id: unifiedSearchResultSkeletonItemDetails
     id: unifiedSearchResultSkeletonItemDetails
 
 
-    property int textLeftMargin: Style.unifiedSearchResultTextLeftMargin
-    property int textRightMargin: Style.unifiedSearchResultTextRightMargin
     property int iconWidth: Style.unifiedSearchResultIconWidth
     property int iconWidth: Style.unifiedSearchResultIconWidth
-    property int iconLeftMargin: Style.unifiedSearchResultIconLeftMargin
-
     property int titleFontSize: Style.unifiedSearchResultTitleFontSize
     property int titleFontSize: Style.unifiedSearchResultTitleFontSize
     property int sublineFontSize: Style.unifiedSearchResultSublineFontSize
     property int sublineFontSize: Style.unifiedSearchResultSublineFontSize
 
 
@@ -19,6 +15,7 @@ RowLayout {
     Accessible.name: qsTr("Search result skeleton.").arg(model.index)
     Accessible.name: qsTr("Search result skeleton.").arg(model.index)
 
 
     height: Style.trayWindowHeaderHeight
     height: Style.trayWindowHeaderHeight
+    spacing: Style.trayHorizontalMargin
 
 
     /*
     /*
     * An overview of what goes on here:
     * An overview of what goes on here:
@@ -41,52 +38,16 @@ RowLayout {
     */
     */
 
 
     property color baseGradientColor: Style.lightHover
     property color baseGradientColor: Style.lightHover
-    property color progressGradientColor: Style.darkMode ? Qt.lighter(baseGradientColor, 1.2) : Qt.darker(baseGradientColor, 1.1)
-
     property int animationRectangleWidth: Style.trayWindowWidth
     property int animationRectangleWidth: Style.trayWindowWidth
-    property int animationStartX: -animationRectangleWidth
-    property int animationEndX: animationRectangleWidth
-
-    Component {
-        id: gradientAnimationRectangle
-        Rectangle {
-            width: unifiedSearchResultSkeletonItemDetails.animationRectangleWidth
-            height: parent.height
-            gradient: Gradient {
-                orientation: Gradient.Horizontal
-                GradientStop {
-                    position: 0
-                    color: "transparent"
-                }
-                GradientStop {
-                    position: 0.4
-                    color: unifiedSearchResultSkeletonItemDetails.progressGradientColor
-                }
-                GradientStop {
-                    position: 0.6
-                    color: unifiedSearchResultSkeletonItemDetails.progressGradientColor
-                }
-                GradientStop {
-                    position: 1.0
-                    color: "transparent"
-                }
-            }
-
-            NumberAnimation on x {
-                from: unifiedSearchResultSkeletonItemDetails.animationStartX
-                to: unifiedSearchResultSkeletonItemDetails.animationEndX
-                duration: 1000
-                loops: Animation.Infinite
-                running: true
-            }
-        }
-    }
 
 
     Item {
     Item {
+        property int whiteSpace: (Style.trayListItemIconSize - unifiedSearchResultSkeletonItemDetails.iconWidth)
+
         Layout.preferredWidth: unifiedSearchResultSkeletonItemDetails.iconWidth
         Layout.preferredWidth: unifiedSearchResultSkeletonItemDetails.iconWidth
         Layout.preferredHeight: unifiedSearchResultSkeletonItemDetails.iconWidth
         Layout.preferredHeight: unifiedSearchResultSkeletonItemDetails.iconWidth
-        Layout.leftMargin: unifiedSearchResultSkeletonItemDetails.iconLeftMargin
         Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
         Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
+        Layout.leftMargin: Style.trayHorizontalMargin + (whiteSpace * (0.5 - Style.thumbnailImageSizeReduction))
+        Layout.rightMargin: whiteSpace * (0.5 + Style.thumbnailImageSizeReduction)
 
 
         Rectangle {
         Rectangle {
             id: unifiedSearchResultSkeletonThumbnail
             id: unifiedSearchResultSkeletonThumbnail
@@ -98,7 +59,10 @@ RowLayout {
             Loader {
             Loader {
                 x: mapFromItem(unifiedSearchResultSkeletonItemDetails, 0, 0).x
                 x: mapFromItem(unifiedSearchResultSkeletonItemDetails, 0, 0).x
                 height: parent.height
                 height: parent.height
-                sourceComponent: gradientAnimationRectangle
+                sourceComponent: UnifiedSearchResultItemSkeletonGradientRectangle {
+                    width: unifiedSearchResultSkeletonItemDetails.animationRectangleWidth
+                    height: parent.height
+                }
             }
             }
         }
         }
 
 
@@ -121,9 +85,7 @@ RowLayout {
         id: unifiedSearchResultSkeletonTextContainer
         id: unifiedSearchResultSkeletonTextContainer
 
 
         Layout.fillWidth: true
         Layout.fillWidth: true
-        Layout.leftMargin: unifiedSearchResultSkeletonItemDetails.textLeftMargin
-        Layout.rightMargin: unifiedSearchResultSkeletonItemDetails.textRightMargin
-
+        Layout.rightMargin: Style.trayHorizontalMargin
         spacing: Style.standardSpacing
         spacing: Style.standardSpacing
 
 
         Item {
         Item {
@@ -140,7 +102,10 @@ RowLayout {
                 Loader {
                 Loader {
                     x: mapFromItem(unifiedSearchResultSkeletonItemDetails, 0, 0).x
                     x: mapFromItem(unifiedSearchResultSkeletonItemDetails, 0, 0).x
                     height: parent.height
                     height: parent.height
-                    sourceComponent: gradientAnimationRectangle
+                    sourceComponent: UnifiedSearchResultItemSkeletonGradientRectangle {
+                        width: unifiedSearchResultSkeletonItemDetails.animationRectangleWidth
+                        height: parent.height
+                    }
                 }
                 }
             }
             }
 
 
@@ -173,7 +138,10 @@ RowLayout {
                 Loader {
                 Loader {
                     x: mapFromItem(unifiedSearchResultSkeletonItemDetails, 0, 0).x
                     x: mapFromItem(unifiedSearchResultSkeletonItemDetails, 0, 0).x
                     height: parent.height
                     height: parent.height
-                    sourceComponent: gradientAnimationRectangle
+                    sourceComponent: UnifiedSearchResultItemSkeletonGradientRectangle {
+                        width: unifiedSearchResultSkeletonItemDetails.animationRectangleWidth
+                        height: parent.height
+                    }
                 }
                 }
             }
             }
 
 

+ 54 - 1
src/gui/tray/UnifiedSearchResultItemSkeletonContainer.qml

@@ -1,12 +1,65 @@
 import QtQml 2.15
 import QtQml 2.15
 import QtQuick 2.15
 import QtQuick 2.15
+import QtQuick.Layouts 1.15
+import QtGraphicalEffects 1.15
+
 import Style 1.0
 import Style 1.0
 
 
-Column {
+ColumnLayout {
     id: unifiedSearchResultsListViewSkeletonColumn
     id: unifiedSearchResultsListViewSkeletonColumn
 
 
     property int animationRectangleWidth: Style.trayWindowWidth
     property int animationRectangleWidth: Style.trayWindowWidth
 
 
+    Item {
+        id: placeholderSectionHeader
+
+        property rect textRect: fontMetrics.boundingRect("Dummy text")
+
+        Layout.topMargin: Style.unifiedSearchResultSectionItemVerticalPadding / 2
+        Layout.bottomMargin: Style.unifiedSearchResultSectionItemVerticalPadding / 2
+        Layout.leftMargin: Style.unifiedSearchResultSectionItemLeftPadding
+
+        width: textRect.width
+        height: textRect.height
+
+        FontMetrics {
+            id: fontMetrics
+            font.pixelSize: Style.unifiedSearchResultTitleFontSize
+        }
+
+        Rectangle {
+            id: placeholderSectionHeaderRectangle
+            anchors.fill: parent
+            radius: Style.veryRoundedButtonRadius
+            color: Style.lightHover
+            clip: true
+            visible: false
+
+            Loader {
+                x: mapFromItem(placeholderSectionHeader, 0, 0).x
+                height: parent.height
+                sourceComponent: UnifiedSearchResultItemSkeletonGradientRectangle {
+                    width: unifiedSearchResultsListViewSkeletonColumn.animationRectangleWidth
+                    height: parent.height
+                }
+            }
+        }
+
+        Rectangle {
+            id: placeholderSectionHeaderMask
+            anchors.fill: placeholderSectionHeaderRectangle
+            color: "white"
+            radius: Style.veryRoundedButtonRadius
+            visible: false
+        }
+
+        OpacityMask {
+            anchors.fill: placeholderSectionHeaderRectangle
+            source: placeholderSectionHeaderRectangle
+            maskSource: placeholderSectionHeaderMask
+        }
+    }
+
     Repeater {
     Repeater {
         model: Math.ceil(unifiedSearchResultsListViewSkeletonColumn.height / Style.trayWindowHeaderHeight)
         model: Math.ceil(unifiedSearchResultsListViewSkeletonColumn.height / Style.trayWindowHeaderHeight)
         UnifiedSearchResultItemSkeleton {
         UnifiedSearchResultItemSkeleton {

+ 56 - 0
src/gui/tray/UnifiedSearchResultItemSkeletonGradientRectangle.qml

@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2022 by Claudio Cambra <claudio.cambra@nextcloud.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+
+import QtQml 2.15
+import QtQuick 2.15
+import QtQuick.Layouts 1.15
+import QtGraphicalEffects 1.15
+
+import Style 1.0
+
+Rectangle {
+    id: root
+
+    property color progressGradientColor: Style.darkMode ? Qt.lighter(Style.lightHover, 1.2) : Qt.darker(Style.lightHover, 1.1)
+    property int animationStartX: -width
+    property int animationEndX: width
+
+    gradient: Gradient {
+        orientation: Gradient.Horizontal
+        GradientStop {
+            position: 0
+            color: "transparent"
+        }
+        GradientStop {
+            position: 0.4
+            color: root.progressGradientColor
+        }
+        GradientStop {
+            position: 0.6
+            color: root.progressGradientColor
+        }
+        GradientStop {
+            position: 1.0
+            color: "transparent"
+        }
+    }
+
+    NumberAnimation on x {
+        from: root.animationStartX
+        to: root.animationEndX
+        duration: 1000
+        loops: Animation.Infinite
+        running: true
+    }
+}

+ 6 - 5
src/gui/tray/UnifiedSearchResultListItem.qml

@@ -36,24 +36,25 @@ MouseArea {
     }
     }
 
 
     Loader {
     Loader {
+        anchors.fill: parent
         active: !isFetchMoreTrigger
         active: !isFetchMoreTrigger
         sourceComponent: UnifiedSearchResultItem {
         sourceComponent: UnifiedSearchResultItem {
-            width: unifiedSearchResultMouseArea.width
-            height: unifiedSearchResultMouseArea.height
+            anchors.fill: parent
             title: model.resultTitle
             title: model.resultTitle
             subline: model.subline
             subline: model.subline
             icons: Theme.darkMode ? model.darkIcons : model.lightIcons
             icons: Theme.darkMode ? model.darkIcons : model.lightIcons
+            iconsIsThumbnail: Theme.darkMode ? model.darkIconsIsThumbnail : model.lightIconsIsThumbnail
             iconPlaceholder: Theme.darkMode ? model.darkImagePlaceholder : model.lightImagePlaceholder
             iconPlaceholder: Theme.darkMode ? model.darkImagePlaceholder : model.lightImagePlaceholder
-            isRounded: model.isRounded
+            isRounded: model.isRounded && iconsIsThumbnail
         }
         }
     }
     }
 
 
     Loader {
     Loader {
+        anchors.fill: parent
         active: isFetchMoreTrigger
         active: isFetchMoreTrigger
         sourceComponent: UnifiedSearchResultFetchMoreTrigger {
         sourceComponent: UnifiedSearchResultFetchMoreTrigger {
+            anchors.fill: parent
             isFetchMoreInProgress: unifiedSearchResultMouseArea.isFetchMoreInProgress
             isFetchMoreInProgress: unifiedSearchResultMouseArea.isFetchMoreInProgress
-            width: unifiedSearchResultMouseArea.width
-            height: unifiedSearchResultMouseArea.height
             isWithinViewPort: !unifiedSearchResultMouseArea.isPooled
             isWithinViewPort: !unifiedSearchResultMouseArea.isPooled
         }
         }
     }
     }

+ 3 - 0
src/gui/tray/Window.qml

@@ -741,10 +741,12 @@ ApplicationWindow {
 
 
         Loader {
         Loader {
             id: unifiedSearchResultsListViewSkeletonLoader
             id: unifiedSearchResultsListViewSkeletonLoader
+
             anchors.top: trayWindowUnifiedSearchInputContainer.bottom
             anchors.top: trayWindowUnifiedSearchInputContainer.bottom
             anchors.left: trayWindowMainItem.left
             anchors.left: trayWindowMainItem.left
             anchors.right: trayWindowMainItem.right
             anchors.right: trayWindowMainItem.right
             anchors.bottom: trayWindowMainItem.bottom
             anchors.bottom: trayWindowMainItem.bottom
+            anchors.margins: controlRoot.padding
 
 
             active: !unifiedSearchResultNothingFound.visible &&
             active: !unifiedSearchResultNothingFound.visible &&
                     !unifiedSearchResultsListView.visible &&
                     !unifiedSearchResultsListView.visible &&
@@ -753,6 +755,7 @@ ApplicationWindow {
 
 
             sourceComponent: UnifiedSearchResultItemSkeletonContainer {
             sourceComponent: UnifiedSearchResultItemSkeletonContainer {
                 anchors.fill: parent
                 anchors.fill: parent
+                spacing: unifiedSearchResultsListView.spacing
                 animationRectangleWidth: trayWindow.width
                 animationRectangleWidth: trayWindow.width
             }
             }
         }
         }

+ 2 - 0
src/gui/tray/unifiedsearchresult.h

@@ -44,6 +44,8 @@ struct UnifiedSearchResult
     QUrl _resourceUrl;
     QUrl _resourceUrl;
     QString _darkIcons;
     QString _darkIcons;
     QString _lightIcons;
     QString _lightIcons;
+    bool _darkIconsIsThumbnail;
+    bool _lightIconsIsThumbnail;
     Type _type = Type::Default;
     Type _type = Type::Default;
 };
 };
 }
 }

+ 20 - 9
src/gui/tray/unifiedsearchresultslistmodel.cpp

@@ -155,7 +155,8 @@ QString generateUrlForIcon(const QString &fallbackIcon, const QUrl &serverUrl, c
     return fallbackIconCopy;
     return fallbackIconCopy;
 }
 }
 
 
-QString iconsFromThumbnailAndFallbackIcon(const QString &thumbnailUrl, const QString &fallbackIcon, const QUrl &serverUrl, const bool darkMode)
+// Return image URL and whether it is a thumbnail or not
+std::pair<QString, bool> iconsFromThumbnailAndFallbackIcon(const QString &thumbnailUrl, const QString &fallbackIcon, const QUrl &serverUrl, const bool darkMode)
 {
 {
     if (thumbnailUrl.isEmpty() && fallbackIcon.isEmpty()) {
     if (thumbnailUrl.isEmpty() && fallbackIcon.isEmpty()) {
         return {};
         return {};
@@ -163,7 +164,7 @@ QString iconsFromThumbnailAndFallbackIcon(const QString &thumbnailUrl, const QSt
 
 
     if (serverUrl.isEmpty()) {
     if (serverUrl.isEmpty()) {
         const QStringList listImages = {thumbnailUrl, fallbackIcon};
         const QStringList listImages = {thumbnailUrl, fallbackIcon};
-        return listImages.join(QLatin1Char(';'));
+        return {listImages.join(QLatin1Char(';')), false};
     }
     }
 
 
     const auto urlForThumbnail = generateUrlForThumbnail(thumbnailUrl, serverUrl);
     const auto urlForThumbnail = generateUrlForThumbnail(thumbnailUrl, serverUrl);
@@ -172,15 +173,15 @@ QString iconsFromThumbnailAndFallbackIcon(const QString &thumbnailUrl, const QSt
     qDebug() << "SEARCH" << urlForThumbnail << urlForFallbackIcon;
     qDebug() << "SEARCH" << urlForThumbnail << urlForFallbackIcon;
 
 
     if (urlForThumbnail.isEmpty() && !urlForFallbackIcon.isEmpty()) {
     if (urlForThumbnail.isEmpty() && !urlForFallbackIcon.isEmpty()) {
-        return urlForFallbackIcon;
+        return {urlForFallbackIcon, false};
     }
     }
 
 
     if (!urlForThumbnail.isEmpty() && urlForFallbackIcon.isEmpty()) {
     if (!urlForThumbnail.isEmpty() && urlForFallbackIcon.isEmpty()) {
-        return urlForThumbnail;
+        return {urlForThumbnail, true};
     }
     }
 
 
     const QStringList listImages{urlForThumbnail, urlForFallbackIcon};
     const QStringList listImages{urlForThumbnail, urlForFallbackIcon};
-    return listImages.join(QLatin1Char(';'));
+    return {listImages.join(QLatin1Char(';')), true};
 }
 }
 
 
 constexpr int searchTermEditingFinishedSearchStartDelay = 800;
 constexpr int searchTermEditingFinishedSearchStartDelay = 800;
@@ -214,6 +215,10 @@ QVariant UnifiedSearchResultsListModel::data(const QModelIndex &index, int role)
         return _results.at(index.row())._darkIcons;
         return _results.at(index.row())._darkIcons;
     case LightIconsRole:
     case LightIconsRole:
         return _results.at(index.row())._lightIcons;
         return _results.at(index.row())._lightIcons;
+    case DarkIconsIsThumbnailRole:
+        return _results.at(index.row())._darkIconsIsThumbnail;
+    case LightIconsIsThumbnailRole:
+        return _results.at(index.row())._lightIconsIsThumbnail;
     case TitleRole:
     case TitleRole:
         return _results.at(index.row())._title;
         return _results.at(index.row())._title;
     case SublineRole:
     case SublineRole:
@@ -247,6 +252,8 @@ QHash<int, QByteArray> UnifiedSearchResultsListModel::roleNames() const
     roles[ProviderIdRole] = "providerId";
     roles[ProviderIdRole] = "providerId";
     roles[DarkIconsRole] = "darkIcons";
     roles[DarkIconsRole] = "darkIcons";
     roles[LightIconsRole] = "lightIcons";
     roles[LightIconsRole] = "lightIcons";
+    roles[DarkIconsIsThumbnailRole] = "darkIconsIsThumbnail";
+    roles[LightIconsIsThumbnailRole] = "lightIconsIsThumbnail";
     roles[DarkImagePlaceholderRole] = "darkImagePlaceholder";
     roles[DarkImagePlaceholderRole] = "darkImagePlaceholder";
     roles[LightImagePlaceholderRole] = "lightImagePlaceholder";
     roles[LightImagePlaceholderRole] = "lightImagePlaceholder";
     roles[TitleRole] = "resultTitle";
     roles[TitleRole] = "resultTitle";
@@ -585,10 +592,14 @@ void UnifiedSearchResultsListModel::parseResultsForProvider(const QJsonObject &d
         const auto accountUrl = (_accountState && _accountState->account()) ? _accountState->account()->url() : QUrl();
         const auto accountUrl = (_accountState && _accountState->account()) ? _accountState->account()->url() : QUrl();
 
 
         result._resourceUrl = makeResourceUrl(resourceUrl, accountUrl);
         result._resourceUrl = makeResourceUrl(resourceUrl, accountUrl);
-        result._darkIcons = iconsFromThumbnailAndFallbackIcon(entryMap.value(QStringLiteral("thumbnailUrl")).toString(),
-            entryMap.value(QStringLiteral("icon")).toString(), accountUrl, true);
-        result._lightIcons = iconsFromThumbnailAndFallbackIcon(entryMap.value(QStringLiteral("thumbnailUrl")).toString(),
-            entryMap.value(QStringLiteral("icon")).toString(), accountUrl, false);
+        const auto darkIconsData = iconsFromThumbnailAndFallbackIcon(entryMap.value(QStringLiteral("thumbnailUrl")).toString(),
+                                                                     entryMap.value(QStringLiteral("icon")).toString(), accountUrl, true);
+        const auto lightIconsData = iconsFromThumbnailAndFallbackIcon(entryMap.value(QStringLiteral("thumbnailUrl")).toString(),
+                                                                      entryMap.value(QStringLiteral("icon")).toString(), accountUrl, false);
+        result._darkIcons = darkIconsData.first;
+        result._lightIcons = lightIconsData.first;
+        result._darkIconsIsThumbnail = darkIconsData.second;
+        result._lightIconsIsThumbnail = lightIconsData.second;
 
 
         newEntries.push_back(result);
         newEntries.push_back(result);
     }
     }

+ 2 - 0
src/gui/tray/unifiedsearchresultslistmodel.h

@@ -57,6 +57,8 @@ public:
         LightImagePlaceholderRole,
         LightImagePlaceholderRole,
         DarkIconsRole,
         DarkIconsRole,
         LightIconsRole,
         LightIconsRole,
+        DarkIconsIsThumbnailRole,
+        LightIconsIsThumbnailRole,
         TitleRole,
         TitleRole,
         SublineRole,
         SublineRole,
         ResourceUrlRole,
         ResourceUrlRole,

+ 4 - 3
theme/Style/Style.qml

@@ -88,7 +88,7 @@ QtObject {
 
 
     property int roundButtonBackgroundVerticalMargins: 10
     property int roundButtonBackgroundVerticalMargins: 10
     property int roundedButtonBackgroundVerticalMargins: 5
     property int roundedButtonBackgroundVerticalMargins: 5
-    
+
     property int userStatusEmojiSize: 8
     property int userStatusEmojiSize: 8
     property int userStatusSpacing: trayHorizontalMargin
     property int userStatusSpacing: trayHorizontalMargin
     property int userStatusAnchorsMargin: 2
     property int userStatusAnchorsMargin: 2
@@ -105,7 +105,8 @@ QtObject {
     readonly property int unifiedSearchItemHeight: trayWindowHeaderHeight
     readonly property int unifiedSearchItemHeight: trayWindowHeaderHeight
     readonly property int unifiedSearchResultTextLeftMargin: 18
     readonly property int unifiedSearchResultTextLeftMargin: 18
     readonly property int unifiedSearchResultTextRightMargin: 16
     readonly property int unifiedSearchResultTextRightMargin: 16
-    readonly property int unifiedSearchResultIconWidth: 24
+    readonly property int unifiedSearchResultIconWidth: trayListItemIconSize * (1 - thumbnailImageSizeReduction)
+    readonly property int unifiedSearchResultSmallIconWidth: trayListItemIconSize * (1 - thumbnailImageSizeReduction * 2)
     readonly property int unifiedSearchResultIconLeftMargin: 12
     readonly property int unifiedSearchResultIconLeftMargin: 12
     readonly property int unifiedSearchResultTitleFontSize: topLinePixelSize
     readonly property int unifiedSearchResultTitleFontSize: topLinePixelSize
     readonly property int unifiedSearchResultSublineFontSize: subLinePixelSize
     readonly property int unifiedSearchResultSublineFontSize: subLinePixelSize
@@ -118,6 +119,6 @@ QtObject {
     readonly property int activityContentSpace: 4
     readonly property int activityContentSpace: 4
 
 
     function variableSize(size) {
     function variableSize(size) {
-        return size * (1 + Math.min(pixelSize / 100, 1));       
+        return size * (1 + Math.min(pixelSize / 100, 1));
     }
     }
 }
 }