@@ -138,6 +138,43 @@ var kArtShapeHolderCode = 'Item { \n\
141+// %1 is anchors.fill
144+var kAudioButtonCode = 'AbstractButton { \n\
145+ id: audioButton; \n\
146+ anchors.fill: %1; \n\
149+ readonly property url source: (cardData["quickPreviewData"] && cardData["quickPreviewData"]["uri"]) || ""; \n\
151+ anchors.fill: parent; \n\
152+ visible: parent.pressed; \n\
153+ radius: "medium"; \n\
156+ anchors.fill: parent; \n\
157+ anchors.margins: parent.height > units.gu(5) ? units.gu(2) : 0; \n\
159+ name: DashAudioPlayer.playing && AudioUrlComparer.compare(parent.source, DashAudioPlayer.currentSource) ? "media-playback-pause" : "media-playback-start"; \n\
162+ if (AudioUrlComparer.compare(source, DashAudioPlayer.currentSource)) { \n\
163+ if (DashAudioPlayer.playing) { \n\
164+ DashAudioPlayer.pause(); \n\
166+ DashAudioPlayer.play(); \n\
169+ var playlist = (cardData["quickPreviewData"] && cardData["quickPreviewData"]["playlist"]) || null; \n\
170+ DashAudioPlayer.playSource(source, playlist); \n\
173+ onPressAndHold: { \n\
174+ root.pressAndHold(); \n\
141var kOverlayLoaderCode = 'Loader { \n\
178var kOverlayLoaderCode = 'Loader { \n\
142 id: overlayLoader; \n\
179 id: overlayLoader; \n\
143 readonly property real overlayHeight: (fixedHeaderHeight > 0 ? fixedHeaderHeight : headerHeight) + units.gu(2); \n\
180 readonly property real overlayHeight: (fixedHeaderHeight > 0 ? fixedHeaderHeight : headerHeight) + units.gu(2); \n\
@@ -319,6 +356,22 @@ var kSummaryLabelCode = 'Label { \n\
319 color: %3; \n\
356 color: %3; \n\
359+// %1 is used as bottom anchor of audio progress bar
360+// %2 is used as left anchor of audio progress bar
361+// %3 is used as text color
362+var kAudioProgressBarCode = 'CardAudioProgress { \n\
363+ id: audioProgressBar; \n\
364+ duration: (cardData["quickPreviewData"] && cardData["quickPreviewData"]["duration"]) || 0; \n\
365+ source: (cardData["quickPreviewData"] && cardData["quickPreviewData"]["uri"]) || ""; \n\
369+ right: parent.right; \n\
370+ margins: units.gu(1); \n\
322function cardString(template, components) {
375function cardString(template, components) {
323 var code;
376 var code;
@@ -354,7 +407,20 @@ function cardString(template, components) {
354 var headerAsOverlay = hasArt && template && template["overlay"] === true && (hasTitle || hasMascot);
407 var headerAsOverlay = hasArt && template && template["overlay"] === true && (hasTitle || hasMascot);
355 var hasSubtitle = hasTitle && components["subtitle"] || false;
408 var hasSubtitle = hasTitle && components["subtitle"] || false;
356 var hasHeaderRow = hasMascot && hasTitle;
409 var hasHeaderRow = hasMascot && hasTitle;
357− var hasAttributes = hasTitle && components["attributes"]["field"] || false;
410+ var hasAttributes = hasTitle && components["attributes"] && components["attributes"]["field"] || false;
411+ var isAudio = template["quick-preview-type"] === "audio";
414+ // For now we only support audio cards with [optional] art, title, subtitle
415+ // in horizontal mode
416+ // Anything else makes it behave not like an audio card
417+ if (hasSummary) isAudio = false;
418+ if (!isHorizontal) isAudio = false;
419+ if (hasMascot) isAudio = false;
420+ if (hasEmblem) isAudio = false;
421+ if (headerAsOverlay) isAudio = false;
422+ if (hasAttributes) isAudio = false;
359 if (hasBackground) {
425 if (hasBackground) {
360 var templateCardBackground = (template && typeof template["card-background"] === "string") ? template["card-background"] : "";
426 var templateCardBackground = (template && typeof template["card-background"] === "string") ? template["card-background"] : "";
@@ -424,17 +490,22 @@ function cardString(template, components) {
424 topMargin: units.gu(1);\n';
490 topMargin: units.gu(1);\n';
427 var headerLeftAnchor;
494 var headerLeftAnchor;
428 var headerLeftAnchorHasMargin = false;
495 var headerLeftAnchorHasMargin = false;
429 if (isHorizontal && hasArt) {
496 if (isHorizontal && hasArt) {
430 headerLeftAnchor = 'left: artShapeHolder.right; \n\
497 headerLeftAnchor = 'left: artShapeHolder.right; \n\
431 leftMargin: units.gu(1);\n';
498 leftMargin: units.gu(1);\n';
432 headerLeftAnchorHasMargin = true;
499 headerLeftAnchorHasMargin = true;
500+ } else if (isHorizontal && isAudio) {
501+ headerLeftAnchor = 'left: audioButton.right; \n\
502+ leftMargin: units.gu(1);\n';
503+ headerLeftAnchorHasMargin = true;
434 headerLeftAnchor = 'left: parent.left;\n';
505 headerLeftAnchor = 'left: parent.left;\n';
437− var touchdownOnArtShape = !hasBackground && hasArt && !hasMascot && !hasSummary;
508+ var touchdownOnArtShape = !hasBackground && hasArt && !hasMascot && !hasSummary && !isAudio;
439 if (hasHeaderRow) {
510 if (hasHeaderRow) {
440 code += 'readonly property int headerHeight: row.height;\n'
511 code += 'readonly property int headerHeight: row.height;\n'
@@ -448,6 +519,14 @@ function cardString(template, components) {
449 code += 'readonly property int headerHeight: attributesRow.height;\n'
520 code += 'readonly property int headerHeight: attributesRow.height;\n'
522+ } else if (isAudio) {
524+ code += 'readonly property int headerHeight: titleLabel.height + subtitleLabel.height + subtitleLabel.anchors.topMargin + audioProgressBar.height + audioProgressBar.anchors.topMargin;\n'
525+ } else if (hasTitle) {
526+ code += 'readonly property int headerHeight: titleLabel.height + audioProgressBar.height + audioProgressBar.anchors.topMargin;\n'
528+ code += 'readonly property int headerHeight: audioProgressBar.height;\n'
451 } else if (hasSubtitle) {
530 } else if (hasSubtitle) {
452 code += 'readonly property int headerHeight: titleLabel.height + subtitleLabel.height + subtitleLabel.anchors.topMargin;\n'
531 code += 'readonly property int headerHeight: titleLabel.height + subtitleLabel.height + subtitleLabel.anchors.topMargin;\n'
453 } else if (hasTitle) {
532 } else if (hasTitle) {
@@ -635,6 +714,30 @@ function cardString(template, components) {
635 code += mascotShapeCode + mascotCode + titleSubtitleCode;
714 code += mascotShapeCode + mascotCode + titleSubtitleCode;
718+ var audioProgressBarLeftAnchor = 'audioButton.right';
719+ var audioProgressBarBottomAnchor = 'audioButton.bottom';
720+ var audioProgressBarTextColor = 'root.scopeStyle ? root.scopeStyle.foreground : theme.palette.normal.baseText';
722+ code += kAudioProgressBarCode.arg(audioProgressBarBottomAnchor)
723+ .arg(audioProgressBarLeftAnchor)
724+ .arg(audioProgressBarTextColor);
726+ var audioButtonAnchorsFill;
727+ var audioButtonWidth;
728+ var audioButtonHeight;
730+ audioButtonAnchorsFill = 'artShapeHolder';
731+ audioButtonWidth = 'undefined';
732+ audioButtonHeight = 'undefined';
734+ audioButtonAnchorsFill = 'undefined';
735+ audioButtonWidth = 'height';
736+ audioButtonHeight = '(root.fixedHeaderHeight > 0 ? root.fixedHeaderHeight : headerHeight) + 2 * units.gu(1)';
738+ code += kAudioButtonCode.arg(audioButtonAnchorsFill).arg(audioButtonWidth).arg(audioButtonHeight);
638 if (hasSummary) {
741 if (hasSummary) {
639 var summaryTopAnchor;
742 var summaryTopAnchor;
640 if (isHorizontal && hasArt) summaryTopAnchor = 'artShapeHolder.bottom';
743 if (isHorizontal && hasArt) summaryTopAnchor = 'artShapeHolder.bottom';
@@ -673,6 +776,8 @@ function cardString(template, components) {
673 var implicitHeight = 'implicitHeight: ';
776 var implicitHeight = 'implicitHeight: ';
674 if (hasSummary) {
777 if (hasSummary) {
675 implicitHeight += 'summary.y + summary.height + units.gu(1);\n';
778 implicitHeight += 'summary.y + summary.height + units.gu(1);\n';
779+ } else if (isAudio) {
780+ implicitHeight += 'audioButton.height;\n';
676 } else if (headerAsOverlay) {
781 } else if (headerAsOverlay) {
677 implicitHeight += 'artShapeHolder.height;\n';
782 implicitHeight += 'artShapeHolder.height;\n';
678 } else if (hasHeaderRow) {
783 } else if (hasHeaderRow) {