@@ -96,6 +96,40 @@ var kArtShapeHolderCode = 'Item { \n\
9696 } \n\
9797 }\n';
9898
99+// %1 is anchors.fill
100+// %2 is width
101+// %3 is height
102+var kAudioButtonCode = 'AbstractButton { \n\
103+ id: audioButton; \n\
104+ anchors.fill: %1; \n\
105+ width: %2; \n\
106+ height: %3; \n\
107+ readonly property url source: (cardData["quickPreviewData"] && cardData["quickPreviewData"]["uri"]) || ""; \n\
108+ UbuntuShape { \n\
109+ anchors.fill: parent; \n\
110+ visible: parent.pressed; \n\
111+ radius: "medium"; \n\
112+ borderSource: "radius_pressed.sci" \n\
113+ } \n\
114+ Icon { \n\
115+ anchors.fill: parent; \n\
116+ anchors.margins: parent.height > units.gu(5) ? units.gu(2) : units.gu(0); \n\
117+ opacity: 0.9; \n\
118+ name: DashAudioPlayer.isCurrentSource(parent.source) && DashAudioPlayer.playing ? "media-playback-pause" : "media-playback-start"; \n\
119+ } \n\
120+ onClicked: { \n\
121+ if (DashAudioPlayer.isCurrentSource(source)) { \n\
122+ if (DashAudioPlayer.playing) { \n\
123+ DashAudioPlayer.pause(); \n\
124+ } else { \n\
125+ DashAudioPlayer.play(); \n\
126+ } \n\
127+ } else { \n\
128+ DashAudioPlayer.playSource(source); \n\
129+ } \n\
130+ } \n\
131+ }';
132+
99133var kOverlayLoaderCode = 'Loader { \n\
100134 id: overlayLoader; \n\
101135 anchors { \n\
@@ -300,6 +334,22 @@ var kSummaryLabelCode = 'Label { \n\
300334 color: %3; \n\
301335 }\n';
302336
337+// %1 is used as bottom anchor of audio progress bar
338+// %2 is used as left anchor of audio progress bar
339+// %3 is used as text color
340+var kAudioProgressBarCode = 'CardAudioProgress { \n\
341+ id: audioProgressBar; \n\
342+ duration: (cardData["quickPreviewData"] && cardData["quickPreviewData"]["duration"]) || 0; \n\
343+ source: (cardData["quickPreviewData"] && cardData["quickPreviewData"]["uri"]) || ""; \n\
344+ anchors { \n\
345+ bottom: %1; \n\
346+ left: %2; \n\
347+ right: parent.right; \n\
348+ margins: units.gu(1); \n\
349+ } \n\
350+ color: %3; \n\
351+ }';
352+
303353function cardString(template, components) {
304354 var code;
305355 code = 'AbstractButton { \n\
@@ -333,6 +383,19 @@ function cardString(template, components) {
333383 var hasSubtitle = hasTitle && components["subtitle"] || false;
334384 var hasHeaderRow = hasMascot && hasTitle;
335385 var hasAttributes = hasTitle && components["attributes"]["field"] || false;
386+ var isAudio = template["quickPreviewType"] === "audio";
387+
388+ if (isAudio) {
389+ // For now we only support audio cards with [optional] art, title, subtitle
390+ // in horizontal mode
391+ // Anything else makes it behave not like an audio card
392+ if (hasSummary) isAudio = false;
393+ if (!isHorizontal) isAudio = false;
394+ if (hasMascot) isAudio = false;
395+ if (hasEmblem) isAudio = false;
396+ if (headerAsOverlay) isAudio = false;
397+ if (hasAttributes) isAudio = false;
398+ }
336399
337400 if (hasBackground) {
338401 code += kBackgroundLoaderCode;
@@ -388,17 +451,22 @@ function cardString(template, components) {
388451 topMargin: units.gu(1);\n';
389452 }
390453 }
454+
391455 var headerLeftAnchor;
392456 var headerLeftAnchorHasMargin = false;
393457 if (isHorizontal && hasArt) {
394458 headerLeftAnchor = 'left: artShapeHolder.right; \n\
395459 leftMargin: units.gu(1);\n';
396460 headerLeftAnchorHasMargin = true;
461+ } else if (isHorizontal && isAudio) {
462+ headerLeftAnchor = 'left: audioButton.right; \n\
463+ leftMargin: units.gu(1);\n';
464+ headerLeftAnchorHasMargin = true;
397465 } else {
398466 headerLeftAnchor = 'left: parent.left;\n';
399467 }
400468
401− var touchdownOnArtShape = !hasBackground && hasArt && !hasMascot && !hasSummary;
469+ var touchdownOnArtShape = !hasBackground && hasArt && !hasMascot && !hasSummary && !isAudio;
402470
403471 if (hasHeaderRow) {
404472 code += 'readonly property int headerHeight: row.height;\n'
@@ -412,6 +480,14 @@ function cardString(template, components) {
412480 } else {
413481 code += 'readonly property int headerHeight: attributesRow.height;\n'
414482 }
483+ } else if (isAudio) {
484+ if (hasSubtitle) {
485+ code += 'readonly property int headerHeight: titleLabel.height + subtitleLabel.height + subtitleLabel.anchors.topMargin + audioProgressBar.height + audioProgressBar.anchors.topMargin;\n'
486+ } else if (hasTitle) {
487+ code += 'readonly property int headerHeight: titleLabel.height + audioProgressBar.height + audioProgressBar.anchors.topMargin;\n'
488+ } else {
489+ code += 'readonly property int headerHeight: audioProgressBar.height;\n'
490+ }
415491 } else if (hasSubtitle) {
416492 code += 'readonly property int headerHeight: titleLabel.height + subtitleLabel.height + subtitleLabel.anchors.topMargin;\n'
417493 } else if (hasTitle) {
@@ -593,6 +669,30 @@ function cardString(template, components) {
593669 code += mascotShapeCode + mascotCode + titleSubtitleCode;
594670 }
595671
672+ if (isAudio) {
673+ var audioProgressBarLeftAnchor = 'audioButton.right';
674+ var audioProgressBarBottomAnchor = 'audioButton.bottom';
675+ var audioProgressBarTextColor = 'root.scopeStyle ? root.scopeStyle.foreground : Theme.palette.normal.baseText';
676+
677+ code += kAudioProgressBarCode.arg(audioProgressBarBottomAnchor)
678+ .arg(audioProgressBarLeftAnchor)
679+ .arg(audioProgressBarTextColor);
680+
681+ var audioButtonAnchorsFill;
682+ var audioButtonWidth;
683+ var audioButtonHeight;
684+ if (hasArt) {
685+ audioButtonAnchorsFill = 'artShapeHolder';
686+ audioButtonWidth = 'undefined';
687+ audioButtonHeight = 'undefined';
688+ } else {
689+ audioButtonAnchorsFill = 'undefined';
690+ audioButtonWidth = 'height';
691+ audioButtonHeight = '(root.fixedHeaderHeight > 0 ? root.fixedHeaderHeight : headerHeight) + 2 * units.gu(1)';
692+ }
693+ code += kAudioButtonCode.arg(audioButtonAnchorsFill).arg(audioButtonWidth).arg(audioButtonHeight);
694+ }
695+
596696 if (hasSummary) {
597697 var summaryTopAnchor;
598698 if (isHorizontal && hasArt) summaryTopAnchor = 'artShapeHolder.bottom';
@@ -631,6 +731,8 @@ function cardString(template, components) {
631731 var implicitHeight = 'implicitHeight: ';
632732 if (hasSummary) {
633733 implicitHeight += 'summary.y + summary.height + units.gu(1);\n';
734+ } else if (isAudio) {
735+ implicitHeight += 'audioButton.height;\n';
634736 } else if (hasHeaderRow) {
635737 implicitHeight += 'row.y + row.height + units.gu(1);\n';
636738 } else if (hasMascot) {