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" />
+
+
+