Bug 1257953 - Update narrate to use new animated icon when speaking. r=Gijs

MozReview-Commit-ID: 4OnlJBmzu5T

--HG--
extra : rebase_source : 8e2b63b3fc8e26ebec6a4624e92b623f88bea458
This commit is contained in:
Eitan Isaacson 2016-04-20 10:38:20 -07:00
parent a1ab150136
commit 7733c185b1
8 changed files with 74 additions and 98 deletions

View File

@ -36,13 +36,59 @@ function NarrateControls(mm, win) {
let dropdown = win.document.createElement("ul"); let dropdown = win.document.createElement("ul");
dropdown.className = "dropdown"; dropdown.className = "dropdown";
dropdown.id = "narrate-dropdown"; dropdown.id = "narrate-dropdown";
// We need inline svg here for the animation to work (bug 908634 & 1190881).
// The style animation can't be scoped (bug 830056).
dropdown.innerHTML = dropdown.innerHTML =
localize`<style scoped> localize`<style scoped>
@import url("chrome://global/skin/narrateControls.css"); @import url("chrome://global/skin/narrateControls.css");
</style> </style>
<li> <li>
<button class="dropdown-toggle button" <button class="dropdown-toggle button" id="narrate-toggle" title="${"narrate"}">
id="narrate-toggle" title="${"narrate"}"></button> <svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="24" height="24" viewBox="0 0 24 24">
<style>
@keyframes grow {
0% { transform: scaleY(1); }
15% { transform: scaleY(1.5); }
15% { transform: scaleY(1.5); }
30% { transform: scaleY(1); }
100% { transform: scaleY(1); }
}
#waveform > rect {
fill: #808080;
}
.speaking #waveform > rect {
fill: #58bf43;
transform-box: fill-box;
transform-origin: 50% 50%;
animation-name: grow;
animation-duration: 1750ms;
animation-iteration-count: infinite;
animation-timing-function: linear;
}
#waveform > rect:nth-child(2) { animation-delay: 250ms; }
#waveform > rect:nth-child(3) { animation-delay: 500ms; }
#waveform > rect:nth-child(4) { animation-delay: 750ms; }
#waveform > rect:nth-child(5) { animation-delay: 1000ms; }
#waveform > rect:nth-child(6) { animation-delay: 1250ms; }
#waveform > rect:nth-child(7) { animation-delay: 1500ms; }
</style>
<g id="waveform">
<rect x="1" y="8" width="2" height="8" rx=".5" ry=".5" />
<rect x="4" y="5" width="2" height="14" rx=".5" ry=".5" />
<rect x="7" y="8" width="2" height="8" rx=".5" ry=".5" />
<rect x="10" y="4" width="2" height="16" rx=".5" ry=".5" />
<rect x="13" y="2" width="2" height="20" rx=".5" ry=".5" />
<rect x="16" y="4" width="2" height="16" rx=".5" ry=".5" />
<rect x="19" y="7" width="2" height="10" rx=".5" ry=".5" />
</g>
</svg>
</button>
</li> </li>
<li class="dropdown-popup"> <li class="dropdown-popup">
<div id="narrate-control" class="narrate-row"> <div id="narrate-control" class="narrate-row">
@ -166,29 +212,15 @@ NarrateControls.prototype = {
}); });
} }
break; break;
case "narrate-toggle":
let dropdown = this._doc.getElementById("narrate-dropdown");
if (dropdown.classList.contains("open")) {
if (this.narrator.speaking) {
this.narrator.stop();
}
// We need to remove "keep-open" class here so that AboutReader
// closes this dropdown properly. This class is eventually removed in
// _updateSpeechControls which gets called after narration stops,
// but that happend asynchronously and is too late.
dropdown.classList.remove("keep-open");
}
break;
} }
}, },
_updateSpeechControls: function(speaking) { _updateSpeechControls: function(speaking) {
let dropdown = this._doc.getElementById("narrate-dropdown"); let dropdown = this._doc.getElementById("narrate-dropdown");
dropdown.classList.toggle("keep-open", speaking); dropdown.classList.toggle("keep-open", speaking);
dropdown.classList.toggle("speaking", speaking);
let startStopButton = this._doc.getElementById("narrate-start-stop"); let startStopButton = this._doc.getElementById("narrate-start-stop");
startStopButton.classList.toggle("speaking", speaking);
startStopButton.title = startStopButton.title =
gStrings.GetStringFromName(speaking ? "stop" : "start"); gStrings.GetStringFromName(speaking ? "stop" : "start");

View File

@ -18,8 +18,8 @@ this.NarrateTestUtils = {
VOICE_SELECTED: "#narrate-voices .options .option.selected", VOICE_SELECTED: "#narrate-voices .options .option.selected",
VOICE_SELECT_LABEL: "#narrate-voices .select-toggle .current-voice", VOICE_SELECT_LABEL: "#narrate-voices .select-toggle .current-voice",
RATE: "#narrate-rate-input", RATE: "#narrate-rate-input",
START: "#narrate-start-stop:not(.speaking)", START: "#narrate-dropdown:not(.speaking) #narrate-start-stop",
STOP: "#narrate-start-stop.speaking", STOP: "#narrate-dropdown.speaking #narrate-start-stop",
BACK: "#narrate-skip-previous", BACK: "#narrate-skip-previous",
FORWARD: "#narrate-skip-next", FORWARD: "#narrate-skip-next",

View File

@ -94,10 +94,15 @@ add_task(function* testNarrate() {
yield promiseEvent; yield promiseEvent;
ok(NarrateTestUtils.isVisible(popup), "popup stays visible after scroll"); ok(NarrateTestUtils.isVisible(popup), "popup stays visible after scroll");
promiseEvent = ContentTaskUtils.waitForEvent(content, "paragraphend");
toggle.click(); toggle.click();
yield promiseEvent;
ok(!NarrateTestUtils.isVisible(popup), "popup is dismissed while speaking"); ok(!NarrateTestUtils.isVisible(popup), "popup is dismissed while speaking");
ok(true, "speech stopped when popup is dismissed"); NarrateTestUtils.isStartedState(content, ok);
promiseEvent = ContentTaskUtils.waitForEvent(content, "paragraphend");
$(NarrateTestUtils.STOP).click();
yield promiseEvent;
yield ContentTaskUtils.waitForCondition(
() => !$(NarrateTestUtils.STOP), "transitioned to stopped state");
NarrateTestUtils.isStoppedState(content, ok);
}); });
}); });

View File

@ -222,7 +222,7 @@ AboutReader.prototype = {
} }
break; break;
case "scroll": case "scroll":
this._closeDropdowns(); this._closeDropdowns(true);
let isScrollingUp = this._scrollOffset > aEvent.pageY; let isScrollingUp = this._scrollOffset > aEvent.pageY;
this._setSystemUIVisibility(isScrollingUp); this._setSystemUIVisibility(isScrollingUp);
this._scrollOffset = aEvent.pageY; this._scrollOffset = aEvent.pageY;
@ -771,10 +771,17 @@ AboutReader.prototype = {
}, },
/* /*
* If the ReaderView has open dropdowns, close them. * If the ReaderView has open dropdowns, close them. If we are closing the
* dropdowns because the page is scrolling, allow popups to stay open with
* the keep-open class.
*/ */
_closeDropdowns: function() { _closeDropdowns: function(scrolling) {
let openDropdowns = this._doc.querySelectorAll(".dropdown.open:not(.keep-open)"); let selector = ".dropdown.open";
if (scrolling) {
selector += ":not(.keep-open)";
}
let openDropdowns = this._doc.querySelectorAll(selector);
for (let dropdown of openDropdowns) { for (let dropdown of openDropdowns) {
dropdown.classList.remove("open"); dropdown.classList.remove("open");
} }

View File

@ -33,8 +33,6 @@ toolkit.jar:
skin/classic/global/narrate/back.svg (../../shared/narrate/back.svg) skin/classic/global/narrate/back.svg (../../shared/narrate/back.svg)
skin/classic/global/narrate/fast.svg (../../shared/narrate/fast.svg) skin/classic/global/narrate/fast.svg (../../shared/narrate/fast.svg)
skin/classic/global/narrate/forward.svg (../../shared/narrate/forward.svg) skin/classic/global/narrate/forward.svg (../../shared/narrate/forward.svg)
skin/classic/global/narrate/narrate.svg (../../shared/narrate/narrate.svg)
skin/classic/global/narrate/narrate-active.svg (../../shared/narrate/narrate-active.svg)
skin/classic/global/narrate/slow.svg (../../shared/narrate/slow.svg) skin/classic/global/narrate/slow.svg (../../shared/narrate/slow.svg)
skin/classic/global/narrate/start.svg (../../shared/narrate/start.svg) skin/classic/global/narrate/start.svg (../../shared/narrate/start.svg)
skin/classic/global/narrate/stop.svg (../../shared/narrate/stop.svg) skin/classic/global/narrate/stop.svg (../../shared/narrate/stop.svg)

View File

@ -1,51 +0,0 @@
<?xml version="1.0"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
<style>
@keyframes grow {
0% { transform: scaleY(1); }
15% { transform: scaleY(1.5); }
15% { transform: scaleY(1.5); }
30% { transform: scaleY(1); }
100% { transform: scaleY(1); }
}
@keyframes shrink {
0% { transform: scaleY(1); }
15% { transform: scaleY(.5); }
15% { transform: scaleY(.5); }
30% { transform: scaleY(1); }
100% { transform: scaleY(1); }
}
.barAnimation {
transform-box: fill-box;
transform-origin: 50% 50%;
animation-name: grow;
animation-duration: 1750ms;
animation-iteration-count: infinite;
animation-timing-function: linear;
}
.barAnimation01 { animation-delay: 0; }
.barAnimation02 { animation-delay: 250ms; }
.barAnimation03 { animation-delay: 500ms; }
.barAnimation04 { animation-delay: 750ms; }
.barAnimation05 { animation-delay: 1000ms; }
.barAnimation06 { animation-delay: 1250ms; }
.barAnimation07 { animation-delay: 1500ms; }
</style>
<g id="glyph-waveform" fill="#58bf43">
<rect x="1" y="8" width="2" height="8" rx=".5" ry=".5" class="barAnimation barAnimation01" />
<rect x="4" y="5" width="2" height="14" rx=".5" ry=".5" class="barAnimation barAnimation02" />
<rect x="7" y="8" width="2" height="8" rx=".5" ry=".5" class="barAnimation barAnimation03" />
<rect x="10" y="4" width="2" height="16" rx=".5" ry=".5" class="barAnimation barAnimation04" />
<rect x="13" y="2" width="2" height="20" rx=".5" ry=".5" class="barAnimation barAnimation05" />
<rect x="16" y="4" width="2" height="16" rx=".5" ry=".5" class="barAnimation barAnimation06" />
<rect x="19" y="7" width="2" height="10" rx=".5" ry=".5" class="barAnimation barAnimation07" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -1,16 +0,0 @@
<?xml version="1.0"?>
<!-- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
<g id="glyph-waveform" fill="#808080">
<rect x="1" y="8" width="2" height="8" rx=".5" ry=".5" />
<rect x="4" y="5" width="2" height="14" rx=".5" ry=".5" />
<rect x="7" y="8" width="2" height="8" rx=".5" ry=".5" />
<rect x="10" y="4" width="2" height="16" rx=".5" ry=".5" />
<rect x="13" y="2" width="2" height="20" rx=".5" ry=".5" />
<rect x="16" y="4" width="2" height="16" rx=".5" ry=".5" />
<rect x="19" y="7" width="2" height="10" rx=".5" ry=".5" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 865 B

View File

@ -2,8 +2,9 @@
--border-color: #e5e5e5; --border-color: #e5e5e5;
} }
#narrate-toggle { #narrate-toggle > svg {
background-image: url("chrome://global/skin/narrate/narrate.svg"); display: block;
margin: 0 8px;
} }
.dropdown-popup button { .dropdown-popup button {
@ -64,7 +65,7 @@
background-image: url("chrome://global/skin/narrate/start.svg"); background-image: url("chrome://global/skin/narrate/start.svg");
} }
#narrate-start-stop.speaking { #narrate-dropdown.speaking #narrate-start-stop {
background-image: url("chrome://global/skin/narrate/stop.svg"); background-image: url("chrome://global/skin/narrate/stop.svg");
} }