OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2017 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 // This Polymer element shows media controls for a route that is currently cast | |
6 // to a device. | |
7 Polymer({ | |
8 is: 'route-controls', | |
9 | |
10 properties: { | |
11 /** | |
12 * The current time displayed in seconds. | |
13 * @type {number} | |
14 */ | |
15 displayedCurrentTime_: { | |
16 type: Number, | |
17 value: 0 | |
18 }, | |
19 | |
20 /** | |
21 * Whether updates for the current time from the browser should be ignored. | |
22 * Set to true when the user is dragging the time slider. | |
23 * @private {boolean} | |
24 */ | |
25 ignoreExternalTimeUpdates_: { | |
mark a. foltz
2017/05/03 21:27:00
This might be clearer as isSeeking_, but I don't f
takumif
2017/05/05 18:57:39
Done.
| |
26 type: Boolean, | |
27 value: false | |
28 }, | |
29 | |
30 /** | |
31 * Whether volume updates from the browser should be ignored. Set to true | |
32 * when the user is dragging the volume slider. | |
33 * @private {boolean} | |
34 */ | |
35 ignoreExternalVolumeUpdates_: { | |
mark a. foltz
2017/05/03 21:27:00
isVolumeChanging_
takumif
2017/05/05 18:57:40
Done.
| |
36 type: Boolean, | |
37 value: false | |
38 }, | |
39 | |
40 /** | |
41 * Whether we have received status updates from the browser for the current | |
42 * route. When this is false, we allow updating the media title based on the | |
43 * route name. | |
mark a. foltz
2017/05/03 21:26:59
I don't follow how a media status update is relate
takumif
2017/05/05 18:57:39
Removed this variable. I wanted to use route descr
| |
44 * @private {boolean} | |
45 */ | |
46 receivedStatusUpdates_: { | |
47 type: Boolean, | |
48 value: false | |
49 }, | |
50 | |
51 /** | |
52 * The route to show. | |
53 * @type {?media_router.Route} | |
mark a. foltz
2017/05/03 21:26:59
Must this be null on construction?
takumif
2017/05/05 18:57:39
Removed.
| |
54 */ | |
55 route: { | |
56 type: Object, | |
57 observer: 'onRouteChange_', | |
58 value: null | |
59 }, | |
60 | |
61 /** | |
62 * The status of the media route shown. External updates are done using | |
63 * updateRouteStatus() to discern from internal updates. | |
mark a. foltz
2017/05/03 21:27:00
s/status/media status/
Can you explain "internal"
takumif
2017/05/05 18:57:40
Removed. This was to discern updates by status obj
| |
64 * @private {?media_router.RouteStatus} | |
65 */ | |
66 routeStatus_: { | |
67 type: Object, | |
68 observer: 'onRouteStatusChange_', | |
69 value: null | |
70 }, | |
71 | |
72 /** | |
73 * The value of the time slider, between 0 and 1. | |
mark a. foltz
2017/05/03 21:26:59
s/time slider/seek bar/
Shouldn't this be in secon
takumif
2017/05/05 18:57:40
Switched to seconds. Also merged with displayedCur
| |
74 * @type {number} | |
75 */ | |
76 timeSliderValue_: { | |
mark a. foltz
2017/05/03 21:26:59
currentTimeFraction_ ?
takumif
2017/05/05 18:57:39
Merged with displayedCurrentTime_
| |
77 type: Number, | |
78 value: 0 | |
79 }, | |
80 | |
81 /** | |
82 * The value of the volume slider, between 0 and 1. | |
mark a. foltz
2017/05/03 21:27:00
s/slider/control/
takumif
2017/05/05 18:57:40
Done.
| |
83 * @type {number} | |
84 */ | |
85 volumeSliderValue_: { | |
86 type: Number, | |
87 value: 0 | |
88 }, | |
89 }, | |
90 | |
91 behaviors: [ | |
92 I18nBehavior, | |
93 ], | |
94 | |
95 /** | |
96 * Gets the duration formatted in HH:MM:SS format. | |
97 * @param {?media_router.RouteStatus} routeStatus | |
98 * @return {string} | |
99 * | |
100 * @private | |
101 */ | |
102 getDuration_: function(routeStatus) { | |
103 return routeStatus ? this.getFormattedTime_(routeStatus.duration) : ''; | |
104 }, | |
105 | |
106 /** | |
107 * Converts a number representing an interval of seconds to a string with | |
108 * HH:MM:SS format. | |
109 * @param {number} timeInSec Must be non-negative. Intervals longer than 100 | |
110 * hours get truncated silently. | |
111 * @return {string} | |
112 * | |
113 * @private | |
114 */ | |
115 getFormattedTime_: function(timeInSec) { | |
116 if (timeInSec < 0) { | |
117 return ''; | |
118 } | |
119 var hours = Math.floor(timeInSec / 3600); | |
mark a. foltz
2017/05/03 21:27:00
s/var/const/
takumif
2017/05/05 18:57:39
The presubmit check tells us to use var instead of
| |
120 var minutes = Math.floor(timeInSec / 60) % 60; | |
121 var seconds = Math.floor(timeInSec) % 60; | |
122 var timeParts = [ | |
123 ('0' + hours).substr(-2), ('0' + minutes).substr(-2), | |
124 ('0' + seconds).substr(-2) | |
125 ]; | |
126 return timeParts.join(':'); | |
mark a. foltz
2017/05/03 21:27:00
This can be combined with the previous line.
takumif
2017/05/05 18:57:39
Done.
| |
127 }, | |
128 | |
129 /** | |
130 * @param {?media_router.RouteStatus} routeStatus | |
131 * @return {string} The value for the icon attribute of the mute/unmute | |
132 * button. | |
133 * | |
134 * @private | |
135 */ | |
136 getMuteUnmuteIcon_: function(routeStatus) { | |
137 return (routeStatus && routeStatus.isMuted) ? 'av:volume-off' : | |
mark a. foltz
2017/05/03 21:27:00
Can we initialize the element with a routeStatus t
takumif
2017/05/05 18:57:39
Done.
| |
138 'av:volume-up'; | |
139 }, | |
140 | |
141 /** | |
142 * @param {?media_router.RouteStatus} routeStatus | |
143 * @return {string} Localized title for the mute/unmute button. | |
144 * | |
145 * @private | |
146 */ | |
147 getMuteUnmuteTitle_: function(routeStatus) { | |
148 return (routeStatus && routeStatus.isMuted) ? this.i18n('unmuteTitle') : | |
149 this.i18n('muteTitle'); | |
150 }, | |
151 | |
152 /** | |
153 * @param {?media_router.RouteStatus} routeStatus | |
154 * @return {string}The value for the icon attribute of the play/pause button. | |
155 * | |
156 * @private | |
157 */ | |
158 getPlayPauseIcon_: function(routeStatus) { | |
159 return (routeStatus && routeStatus.isPaused) ? 'av:play-arrow' : 'av:pause'; | |
160 }, | |
161 | |
162 /** | |
163 * @param {?media_router.RouteStatus} routeStatus | |
164 * @return {string} Localized title for the play/pause button. | |
165 * | |
166 * @private | |
167 */ | |
168 getPlayPauseTitle_: function(routeStatus) { | |
169 return (routeStatus && routeStatus.isPaused) ? this.i18n('playTitle') : | |
170 this.i18n('pauseTitle'); | |
171 }, | |
172 | |
173 /** | |
174 * @param {number} seekPositionRatio The ratio with the duration, which must | |
175 * be between 0 and 1. | |
176 * @param {number} duration The duration in seconds. | |
177 * @return {number} The seek position in seconds. | |
178 * | |
179 * @private | |
180 */ | |
181 getSeekPosition_: function(seekPositionRatio, duration) { | |
mark a. foltz
2017/05/03 21:27:00
getSeekTime_(seekPosition, duration) ?
takumif
2017/05/05 18:57:40
Using seconds in the slider, and removing this fun
| |
182 return duration ? Math.floor(seekPositionRatio * duration) : 0; | |
mark a. foltz
2017/05/03 21:27:00
I don't think this extra check is necessary; Math.
takumif
2017/05/05 18:57:39
Removing.
| |
183 }, | |
184 | |
185 /** | |
186 * @param {number} seekPosition The seek position in seconds. | |
187 * @param {number} duration The duration in seconds. | |
188 * @return {number} The seek position as a ratio with the duration, between 0 | |
189 * and 1. | |
190 * | |
191 * @private | |
192 */ | |
193 getSeekPositionRatio_: function(seekPosition, duration) { | |
mark a. foltz
2017/05/03 21:27:00
getSeekPosition_(seekTime, duration) ?
takumif
2017/05/05 18:57:39
Removing.
| |
194 return duration ? (seekPosition / duration) : 0; | |
195 }, | |
196 | |
197 /** | |
198 * Called when the user starts dragging the current-time slider. | |
199 * @param {!Event} e | |
200 * | |
201 * @private | |
202 */ | |
203 onImmediateTimeSliderChange_: function(e) { | |
mark a. foltz
2017/05/03 21:26:59
onSeekStart_ ?
takumif
2017/05/05 18:57:39
Done.
| |
204 this.ignoreExternalTimeUpdates_ = true; | |
205 /** @type {{immediateValue: number}} */ | |
206 var target = e.target; | |
207 this.timeSliderValue_ = target.immediateValue; | |
208 this.displayedCurrentTime_ = this.getSeekPosition_( | |
209 this.timeSliderValue_, this.routeStatus_.duration); | |
210 }, | |
211 | |
212 /** | |
213 * Called when the user starts dragging the volume slider. | |
214 * @param {!Event} e | |
215 * | |
216 * @private | |
217 */ | |
218 onImmediateVolumeSliderChange_: function(e) { | |
mark a. foltz
2017/05/03 21:27:00
onVolumeChangeStart_?
takumif
2017/05/05 18:57:40
Done.
| |
219 this.ignoreExternalVolumeUpdates_ = true; | |
220 /** @type {{immediateValue: number}} */ | |
221 var target = e.target; | |
222 this.volumeSliderValue_ = target.immediateValue; | |
223 }, | |
224 | |
225 /** | |
226 * Sends a mute or unmute command to the browser. | |
mark a. foltz
2017/05/03 21:27:00
Called when the user toggles the mute status of th
takumif
2017/05/05 18:57:39
Done.
| |
227 * | |
228 * @private | |
229 */ | |
230 onMuteUnmute_: function() { | |
231 media_router.browserApi.setCurrentMediaMute(!this.routeStatus_.isMuted); | |
232 }, | |
233 | |
234 /** | |
235 * Sends a play or pause command to the browser. | |
mark a. foltz
2017/05/03 21:27:00
Called when the user toggles between playing and p
takumif
2017/05/05 18:57:39
Done.
| |
236 * | |
237 * @private | |
238 */ | |
239 onPlayPause_: function() { | |
240 if (this.routeStatus_.isPaused) { | |
241 media_router.browserApi.playCurrentMedia(); | |
242 } else { | |
243 media_router.browserApi.pauseCurrentMedia(); | |
244 } | |
245 }, | |
246 | |
247 /** | |
248 * Updates the route title shown, if no status updates have been received. | |
249 * | |
250 * @private | |
251 */ | |
252 onRouteChange_: function(newRoute) { | |
253 if (!newRoute || this.receivedStatusUpdates_) | |
254 return; | |
255 | |
256 // Hide all the elements except for the title showing the route description. | |
257 this.routeStatus_ = new media_router.RouteStatus( | |
mark a. foltz
2017/05/03 21:27:00
Would this be simpler as just a <div> with text co
takumif
2017/05/05 18:57:39
Creating a displayedDescription_ property to set i
| |
258 loadTimeData.getStringF('castingActivityStatus', newRoute.description), | |
259 '', false, false, false, false, false, false, 0, 0, 0); | |
260 }, | |
261 | |
262 /** | |
263 * Called when the route details view is closed. | |
264 */ | |
265 onRouteDetailsClosed: function() { | |
266 this.receivedStatusUpdates_ = false; | |
267 this.routeStatus_ = null; | |
268 media_router.ui.setRouteControls(null); | |
269 }, | |
270 | |
271 /** | |
272 * Updates seek and volume sliders if the user is not currently dragging on | |
273 * them. | |
274 * @param {?media_router.RouteStatus} newRouteStatus | |
275 * | |
276 * @private | |
277 */ | |
278 onRouteStatusChange_: function(newRouteStatus) { | |
279 if (!newRouteStatus) | |
280 return; | |
281 | |
282 if (!this.ignoreExternalTimeUpdates_) { | |
283 this.displayedCurrentTime_ = newRouteStatus.currentTime; | |
284 this.timeSliderValue_ = this.getSeekPositionRatio_( | |
285 newRouteStatus.currentTime, newRouteStatus.duration); | |
286 } | |
287 | |
288 if (!this.ignoreExternalVolumeUpdates_) { | |
289 this.volumeSliderValue_ = newRouteStatus.volume; | |
290 } | |
291 }, | |
292 | |
293 /** | |
294 * Called when the user clicks on or stops dragging the current-time slider. | |
295 * @param {!Event} e | |
296 * | |
297 * @private | |
298 */ | |
299 onTimeSliderChange_: function(e) { | |
mark a. foltz
2017/05/03 21:27:00
onSeekComplete_
takumif
2017/05/05 18:57:40
Done.
| |
300 if (!this.routeStatus_) | |
301 return; | |
302 | |
303 this.ignoreExternalTimeUpdates_ = false; | |
304 /** @type {{value: number}} */ | |
305 var target = e.target; | |
306 this.timeSliderValue_ = target.value; | |
307 this.displayedCurrentTime_ = this.getSeekPosition_( | |
308 this.timeSliderValue_, this.routeStatus_.duration); | |
309 media_router.browserApi.seekCurrentMedia(this.displayedCurrentTime_); | |
310 }, | |
311 | |
312 /** | |
313 * Called when the user clicks on or stops dragging the volume slider. | |
314 * @param {!Event} e | |
315 * | |
316 * @private | |
317 */ | |
318 onVolumeSliderChange_: function(e) { | |
mark a. foltz
2017/05/03 21:27:00
onVolumeChangeComplete_
takumif
2017/05/05 18:57:39
Done.
| |
319 if (!this.routeStatus_) | |
320 return; | |
321 | |
322 this.ignoreExternalVolumeUpdates_ = false; | |
323 /** @type {{value: number}} */ | |
324 var target = e.target; | |
325 this.volumeSliderValue_ = target.value; | |
326 media_router.browserApi.setCurrentMediaVolume(this.volumeSliderValue_); | |
327 }, | |
328 | |
329 /** | |
330 * Called by Polymer on ready. | |
331 */ | |
332 ready: function() { | |
333 media_router.ui.setRouteControls(this); | |
334 }, | |
335 | |
336 /** | |
337 * Updates the route status that is displayed on the controls. | |
338 * | |
339 * @param {!media_router.RouteStatus} status | |
340 */ | |
341 updateRouteStatus: function(status) { | |
342 this.receivedStatusUpdates_ = true; | |
mark a. foltz
2017/05/03 21:27:00
Is this the same as testing this.routeStatus_ ?
takumif
2017/05/05 18:57:39
Removed.
| |
343 this.routeStatus_ = status; | |
344 }, | |
345 }); | |
OLD | NEW |