From 85c039850c45246e367e194232e5ace8771f14e7 Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sat, 23 Jan 2021 20:24:52 -0500 Subject: [PATCH] Audio play button status badge (#1300) * Add plus-thick.svg * Add success-color variable * Fix icon display * Add badge * Add missing audioResolved * Update audio badge * Expose attribute --- ext/mixed/css/display.css | 16 +++++++++++ ext/mixed/css/material.css | 9 +++++- ext/mixed/display-templates.html | 4 +-- ext/mixed/img/plus-thick.svg | 1 + ext/mixed/js/display-audio.js | 49 +++++++++++++++++++++++++++++++- resources/icons.svg | 19 +++++++++---- 6 files changed, 89 insertions(+), 9 deletions(-) create mode 100644 ext/mixed/img/plus-thick.svg diff --git a/ext/mixed/css/display.css b/ext/mixed/css/display.css index ccdb2d9c..003d0962 100644 --- a/ext/mixed/css/display.css +++ b/ext/mixed/css/display.css @@ -551,6 +551,7 @@ button.action-button { background: transparent; font-size: inherit; box-shadow: none; + position: relative; transition: opacity var(--animation-duration) linear, visibility 0s linear 0s, @@ -615,6 +616,21 @@ button.action-button[data-icon=source-term]::before { .entry[data-type=term][data-expression-multi=true] .actions>button.action-button.action-play-audio { display: none; } +.action-button-badge { + pointer-events: none; + position: absolute; + display: block; + right: 0; + top: 0; + width: calc(8em / var(--font-size-no-units)); + height: calc(8em / var(--font-size-no-units)); +} +.action-button-badge[data-icon=cross] { + background-color: var(--danger-color); +} +.action-button-badge[data-icon=plus-thick] { + background-color: var(--success-color); +} /* Tags */ diff --git a/ext/mixed/css/material.css b/ext/mixed/css/material.css index 7da515b5..c9277088 100644 --- a/ext/mixed/css/material.css +++ b/ext/mixed/css/material.css @@ -79,6 +79,8 @@ --danger-color-transparent5: rgba(200, 60, 40, 0.05); --danger-color-transparent25: rgba(200, 60, 40, 0.25); + --success-color: #51ab30; + --disabled-color: #aaaaaa; --disabled-color-light: #dddddd; --disabled-color-lighter: #eeeeee; @@ -135,6 +137,8 @@ --danger-color-transparent5: rgba(221, 103, 85, 0.05); --danger-color-transparent25: rgba(221, 103, 85, 0.25); + --success-color: #75cf54; + --disabled-color: #444444; --disabled-color-light: #585858; --disabled-color-lighter: #777777; @@ -209,6 +213,7 @@ .icon[data-icon=question-mark-thick] { --icon-image: url(/mixed/img/question-mark-thick.svg); } .icon[data-icon=left-chevron] { --icon-image: url(/mixed/img/left-chevron.svg); } .icon[data-icon=right-chevron] { --icon-image: url(/mixed/img/right-chevron.svg); } +.icon[data-icon=plus-thick] { --icon-image: url(/mixed/img/plus-thick.svg); } .icon[data-icon=material-down-arrow] { --icon-image: url(/mixed/img/material-down-arrow.svg); --icon-size: var(--material-arrow-dimension2) var(--material-arrow-dimension1); @@ -959,12 +964,14 @@ button.popup-menu-item:disabled { color: var(--text-color-light2); } .popup-menu-item-icon { - display: block; width: calc(16em / 14); height: calc(16em / 14); background-color: var(--text-color); margin-right: 0.5em; } +.popup-menu-item-icon:not([hidden]) { + display: block; +} :root[data-page-type=popup] .popup-menu.popup-menu-auto-size, .popup-menu.popup-menu-small { border-radius: calc(var(--menu-border-radius) * 0.75); diff --git a/ext/mixed/display-templates.html b/ext/mixed/display-templates.html index c261bcdb..40716469 100644 --- a/ext/mixed/display-templates.html +++ b/ext/mixed/display-templates.html @@ -10,7 +10,7 @@ - +
@@ -44,7 +44,7 @@
- +
diff --git a/ext/mixed/img/plus-thick.svg b/ext/mixed/img/plus-thick.svg new file mode 100644 index 00000000..6b1b5c5a --- /dev/null +++ b/ext/mixed/img/plus-thick.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/ext/mixed/js/display-audio.js b/ext/mixed/js/display-audio.js index 2d95eea4..e1a9e250 100644 --- a/ext/mixed/js/display-audio.js +++ b/ext/mixed/js/display-audio.js @@ -135,9 +135,11 @@ class DisplayAudio { this.stopAudio(); // Update details + const potentialAvailableAudioCount = this._getPotentialAvailableAudioCount(expression, reading); for (const button of this._getAudioPlayButtons(definitionIndex, expressionIndex)) { const titleDefault = button.dataset.titleDefault || ''; button.title = `${titleDefault}\n${title}`; + this._updateAudioPlayButtonBadge(button, potentialAvailableAudioCount); } // Play @@ -277,7 +279,7 @@ class DisplayAudio { async _getExpressionAudioInfoList(source, expression, reading, details) { const infoList = await api.getExpressionAudioInfoList(source, expression, reading, details); - return infoList.map((info) => ({info, audioPromise: null, audio: null})); + return infoList.map((info) => ({info, audioPromise: null, audioResolved: false, audio: null})); } _getExpressionAndReading(definitionIndex, expressionIndex) { @@ -313,4 +315,49 @@ class DisplayAudio { _clamp(value, min, max) { return Math.max(min, Math.min(max, value)); } + + _updateAudioPlayButtonBadge(button, potentialAvailableAudioCount) { + if (potentialAvailableAudioCount === null) { + delete button.dataset.potentialAvailableAudioCount; + } else { + button.dataset.potentialAvailableAudioCount = `${potentialAvailableAudioCount}`; + } + + const badge = button.querySelector('.action-button-badge'); + if (badge === null) { return; } + + const badgeData = badge.dataset; + switch (potentialAvailableAudioCount) { + case 0: + badgeData.icon = 'cross'; + badgeData.hidden = false; + break; + case 1: + case null: + delete badgeData.icon; + badgeData.hidden = true; + break; + default: + badgeData.icon = 'plus-thick'; + badgeData.hidden = false; + break; + } + } + + _getPotentialAvailableAudioCount(expression, reading) { + const key = this._getExpressionReadingKey(expression, reading); + const sourceMap = this._cache.get(key); + if (typeof sourceMap === 'undefined') { return null; } + + let count = 0; + for (const {infoList} of sourceMap.values()) { + if (infoList === null) { continue; } + for (const {audio, audioResolved} of infoList) { + if (!audioResolved || audio !== null) { + ++count; + } + } + } + return count; + } } diff --git a/resources/icons.svg b/resources/icons.svg index 5d5ac89e..0ace4793 100644 --- a/resources/icons.svg +++ b/resources/icons.svg @@ -27,11 +27,11 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="32" - inkscape:cx="10.107295" - inkscape:cy="8.7280255" + inkscape:zoom="45.254834" + inkscape:cx="8.4539164" + inkscape:cy="8.0625778" inkscape:document-units="px" - inkscape:current-layer="layer41" + inkscape:current-layer="layer49" showgrid="true" units="px" inkscape:snap-center="true" @@ -1536,7 +1536,7 @@ inkscape:connector-curvature="0" /> @@ -1547,4 +1547,13 @@ d="M 6.4999999,13 14.5,5 l -2,-2 -6.0000001,6 -3,-3 -2,2 z" style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> + + +