Advertisement
Guest User

Untitled

a guest
Mar 25th, 2024
23
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.02 KB | None | 0 0
  1. /*
  2. SPDX-FileCopyrightText: 2013 Marco Martin <mart@kde.org>
  3. SPDX-FileCopyrightText: 2014 Sebastian Kügler <sebas@kde.org>
  4. SPDX-FileCopyrightText: 2014 Kai Uwe Broulik <kde@privat.broulik.de>
  5.  
  6. SPDX-License-Identifier: GPL-2.0-or-later
  7. */
  8.  
  9. import QtQuick 2.15
  10. import QtQuick.Controls 2.15
  11. import QtQuick.Window 2.15
  12.  
  13. import org.kde.plasma.plasmoid 2.0
  14. import org.kde.plasma.components 3.0 as PC3
  15. import org.kde.plasma.extras 2.0 as PlasmaExtras
  16. import org.kde.plasma.private.mpris as Mpris
  17. import org.kde.kirigami 2.20 as Kirigami
  18.  
  19. Item {
  20. id: container
  21.  
  22. /**
  23. * Whether the album art image is available or in loading status
  24. */
  25. readonly property bool hasImage: (pendingImage !== null && (pendingImage.status === Image.Ready || pendingImage.status === Image.Loading))
  26. || (albumArt.currentItem instanceof Image && albumArt.currentItem.status === Image.Ready)
  27.  
  28. readonly property bool animating: exitTransition.running || popExitTransition.running
  29.  
  30. /**
  31. * Whether the component is used in the compact representation
  32. */
  33. property bool inCompactRepresentation: false
  34.  
  35. /**
  36. * Provides source item for \ShaderEffectSource
  37. */
  38. readonly property alias albumArt: albumArt
  39.  
  40. property Image pendingImage: null
  41.  
  42. function loadAlbumArt() {
  43. if (pendingImage !== null) {
  44. pendingImage.destroy();
  45. pendingImage = null;
  46. }
  47.  
  48. if (!root.albumArt) {
  49. albumArt.clear(StackView.PopTransition);
  50. return;
  51. }
  52.  
  53. const oldImageRatio = albumArt.currentItem instanceof Image ? albumArt.currentItem.sourceSize.width / albumArt.currentItem.sourceSize.height : 1;
  54. pendingImage = albumArtComponent.createObject(albumArt, {
  55. "source": root.albumArt,
  56. "sourceSize": Qt.size(container.width * Screen.devicePixelRatio, container.height * Screen.devicePixelRatio),
  57. "opacity": 0,
  58. });
  59.  
  60. function replaceWhenLoaded() {
  61. // There can be a potential race: when the previous player is gone but the pending image is just ready in time,
  62. // pendingImage.destroy() -> QQuickImage::deleteLater(), so in the event queue statusChanged may be emitted
  63. // before pendingImage is deleted, but pendingImage is already set to null when the previous player is gone.
  64. if (pendingImage === null || pendingImage.status === Image.Loading) {
  65. return;
  66. }
  67.  
  68. if (pendingImage.status === Image.Ready) {
  69. const newImageRatio = pendingImage.sourceSize.width / pendingImage.sourceSize.height;
  70. exitTransitionOpacityAnimator.duration = oldImageRatio === newImageRatio ? 0 : Kirigami.Units.longDuration;
  71. } else {
  72. // Load placeholder icon, but keep the invalid image to avoid flashing application icons
  73. exitTransitionOpacityAnimator.duration = 0;
  74. }
  75.  
  76. pendingImage.statusChanged.disconnect(replaceWhenLoaded);
  77. albumArt.replace(pendingImage, {}, StackView.ReplaceTransition);
  78. pendingImage = null;
  79. }
  80.  
  81. pendingImage.statusChanged.connect(replaceWhenLoaded);
  82. replaceWhenLoaded();
  83. }
  84.  
  85. Connections {
  86. enabled: root.expanded // BUG 477866
  87. target: container
  88. function onWidthChanged() {
  89. geometryChangeTimer.restart();
  90. }
  91. function onHeightChanged() {
  92. geometryChangeTimer.restart();
  93. }
  94. }
  95.  
  96. // Reload album art when size of container changes
  97. Timer {
  98. id: geometryChangeTimer
  99. interval: 250
  100. onTriggered: container.loadAlbumArt();
  101. }
  102.  
  103. StackView {
  104. id: albumArt
  105.  
  106. anchors.fill: parent
  107.  
  108. readonly property string icon: root.iconName || "media-album-cover"
  109.  
  110. replaceEnter: Transition {
  111. OpacityAnimator {
  112. from: 0
  113. to: 1
  114. duration: Kirigami.Units.longDuration
  115. }
  116. }
  117.  
  118. replaceExit: Transition {
  119. id: exitTransition
  120.  
  121. SequentialAnimation {
  122. PauseAnimation {
  123. duration: Kirigami.Units.longDuration
  124. }
  125.  
  126. /**
  127. * If the new ratio and the old ratio are different,
  128. * perform a fade-out animation for the old image
  129. * to prevent it from suddenly disappearing.
  130. */
  131. OpacityAnimator {
  132. id: exitTransitionOpacityAnimator
  133. from: 1
  134. to: 0
  135. duration: 0
  136. }
  137. }
  138. }
  139.  
  140. popExit: Transition {
  141. id: popExitTransition
  142.  
  143. OpacityAnimator {
  144. from: 1
  145. to: 0
  146. duration: Kirigami.Units.longDuration
  147. }
  148. }
  149.  
  150. Component {
  151. id: albumArtComponent
  152.  
  153. Image { // Album Art
  154. horizontalAlignment: Image.AlignHCenter
  155. verticalAlignment: Image.AlignVCenter
  156. fillMode: container.inCompactRepresentation ? Image.PreserveAspectCrop : Image.PreserveAspectFit
  157.  
  158. asynchronous: true
  159. cache: false
  160.  
  161. // onRemoved only fires when all transitions end. If a user switches songs quickly this adds up
  162. // Given it's such a heavy item, try to cleanup as early as possible
  163. StackView.onDeactivated: destroy()
  164. StackView.onRemoved: destroy()
  165. }
  166. }
  167.  
  168. Component {
  169. id: fallbackIconItem
  170.  
  171. Kirigami.Icon { // Fallback
  172. id: fallbackIcon
  173.  
  174. anchors.margins: Kirigami.Units.gridUnit * 2
  175. opacity: 0
  176. source: albumArt.icon
  177.  
  178. NumberAnimation {
  179. duration: Kirigami.Units.longDuration
  180. easing.type: Easing.OutCubic
  181. property: "opacity"
  182. running: true
  183. target: fallbackIcon
  184. to: 1
  185. }
  186. }
  187. }
  188.  
  189. // "No media playing" placeholder message
  190. Component {
  191. id: placeholderMessage
  192.  
  193. // Put PlaceholderMessage in Item so PlaceholderMessage will not fill its parent.
  194. Item {
  195. property alias source: message.iconName
  196.  
  197. PlasmaExtras.PlaceholderMessage {
  198. id: message
  199. anchors.centerIn: parent
  200. width: parent.width // For text wrap
  201. iconName: albumArt.icon
  202. text: root.playbackStatus > Mpris.PlaybackStatus.Stopped ? i18n("No title") : i18n("No media playing")
  203. }
  204. }
  205. }
  206.  
  207. Component {
  208. id: busyComponent
  209.  
  210. Item {
  211. PC3.BusyIndicator {
  212. id: busyIndicator
  213. anchors.centerIn: parent
  214. running: false
  215. }
  216.  
  217. SequentialAnimation {
  218. running: true
  219.  
  220. PauseAnimation {
  221. duration: Kirigami.Units.longDuration
  222. }
  223. PropertyAction {
  224. property: "running"
  225. target: busyIndicator
  226. value: true
  227. }
  228. }
  229. }
  230.  
  231. }
  232. }
  233.  
  234. Loader {
  235. anchors.fill: parent
  236. visible: active
  237.  
  238. readonly property bool isLoadingImage: pendingImage !== null && pendingImage.status === Image.Loading
  239.  
  240. active: (inCompactRepresentation || root.expanded) && (!container.hasImage || isLoadingImage)
  241. asynchronous: true
  242. sourceComponent: root.track ? (isLoadingImage ? busyComponent : fallbackIconItem) : placeholderMessage
  243. }
  244. }
  245.  
  246.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement