Warning, /multimedia/kasts/src/qml/ImageWithFallback.qml is written in an unsupported language. File is not indexed.

0001 /**
0002  * SPDX-FileCopyrightText: 2021-2023 Bart De Vries <bart@mogwai.be>
0003  *
0004  * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005  */
0006 
0007 import QtQuick
0008 import QtQuick.Controls as Controls
0009 import QtQuick.Layouts
0010 import QtQuick.Effects
0011 import QtQuick.Window
0012 
0013 import org.kde.kirigami as Kirigami
0014 
0015 import org.kde.kasts
0016 import org.kde.kasts.settings
0017 
0018 Item {
0019     id: root
0020     property string imageSource: "no-image"
0021     property real imageOpacity: 1
0022     property int absoluteRadius: 0
0023     property real fractionalRadius: 0.0
0024     property string imageTitle: ""
0025     property bool isLoading: false
0026     property int imageFillMode: Image.PreserveAspectCrop
0027     property bool imageResize: true
0028     property bool mipmap: false
0029 
0030     // HACK: if mipmap has been set to true, then reset it AFTER image has
0031     // changed, otherwise it will be ignored
0032     onImageSourceChanged: {
0033         if (root.mipmap) {
0034             root.mipmap = true;
0035         }
0036     }
0037 
0038     Loader {
0039         id: imageLoader
0040         anchors.fill: parent
0041         visible: false
0042         sourceComponent: (imageSource === "no-image" || imageSource === "") ? fallbackImg : (imageSource === "fetching" ? loaderSymbol : realImg )
0043     }
0044 
0045     MultiEffect {
0046         anchors.fill: parent
0047         source: imageLoader.item
0048         opacity: root.imageOpacity
0049         maskEnabled: true
0050         maskThresholdMin: 0.5
0051         maskSpreadAtMin: 0.5
0052         maskSource: ShaderEffectSource {
0053             width: imageLoader.width
0054             height: imageLoader.height
0055             sourceItem: Rectangle {
0056                 anchors.centerIn: parent
0057                 width: imageLoader.adapt ? imageLoader.width : Math.min(imageLoader.width, imageLoader.height)
0058                 height: imageLoader.adapt ? imageLoader.height : width
0059                 radius: (absoluteRadius > 0) ? absoluteRadius : ( (fractionalRadius > 0) ? Math.min(width, height)*fractionalRadius : 0 )
0060             }
0061         }
0062     }
0063 
0064     Component {
0065         id: realImg
0066         Image {
0067             anchors.fill: parent
0068             source: root.imageSource
0069             fillMode: root.imageFillMode
0070             sourceSize.width: root.imageResize ? width * Screen.devicePixelRatio : 0
0071             sourceSize.height: root.imageResize ? height * Screen.devicePixelRatio : 0
0072             asynchronous: true
0073             mipmap: root.mipmap
0074         }
0075     }
0076 
0077     Component {
0078         id: fallbackImg
0079         Item {
0080             anchors.fill: parent
0081             // Add white background color in order to use coloroverlay later on
0082             Rectangle {
0083                 anchors.fill: parent
0084                 color: "white"
0085             }
0086             Kirigami.Icon {
0087                 anchors.fill: parent
0088                 source: "rss"
0089                 isMask: true
0090                 color: "black"
0091             }
0092         }
0093     }
0094 
0095     Component {
0096         id: imageText
0097         Item {
0098             Rectangle {
0099                 anchors.fill: header
0100                 opacity: 0.5
0101                 color: "black"
0102             }
0103 
0104             Kirigami.Heading {
0105                 id: header
0106                 anchors.bottom: parent.bottom
0107                 anchors.left: parent.left
0108                 anchors.right: parent.right
0109                 padding: 10
0110                 text: root.imageTitle
0111                 level: 3
0112                 font.bold: true
0113                 color: "white"
0114                 wrapMode: Text.Wrap
0115                 elide: Text.ElideRight
0116             }
0117         }
0118     }
0119 
0120     Loader {
0121         anchors.fill: parent
0122         active: root.imageTitle !== "" && (SettingsManager.alwaysShowFeedTitles ? true : (imageSource === "no-image" || imageSource === "fetching"))
0123         sourceComponent: imageText
0124     }
0125 
0126     Component {
0127         id: loaderSymbol
0128         Item {
0129             anchors.fill: parent
0130             Rectangle {
0131                 color: "white"
0132                 opacity: 0.5
0133                 anchors.fill: parent
0134             }
0135             Controls.BusyIndicator {
0136                 anchors.centerIn: parent
0137                 width: parent.width / 2
0138                 height: parent.height / 2
0139             }
0140         }
0141     }
0142 
0143     Loader {
0144         active: isLoading
0145         sourceComponent: loaderSymbol
0146         anchors.fill: parent
0147     }
0148 }