Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(92)

Side by Side Diff: chrome/browser/resources/media_router/elements/route_details/route_details.js

Issue 2725503002: [Media Router] Custom Controls 4 - Implement details view WebUI (Closed)
Patch Set: . Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 // This Polymer element shows information from media that is currently cast 5 // This Polymer element shows information from media that is currently cast
6 // to a device. 6 // to a device.
7 Polymer({ 7 Polymer({
8 is: 'route-details', 8 is: 'route-details',
9 9
10 properties: { 10 properties: {
11 /** 11 /**
12 * The text for the current casting activity status. 12 * The text for the current casting activity status.
13 * @private {string|undefined} 13 * @private {string|undefined}
14 */ 14 */
15 activityStatus_: { 15 activityStatus_: {
16 type: String, 16 type: String,
17 }, 17 },
18 18
19 /** 19 /**
20 * Whether the external container will accept change-route-source-click 20 * Whether the external container will accept change-route-source-click
21 * events. 21 * events.
22 * @private {boolean} 22 * @private {boolean}
23 */ 23 */
24 changeRouteSourceAvailable_: { 24 changeRouteSourceAvailable_: {
25 type: Boolean, 25 type: Boolean,
26 computed: 'computeChangeRouteSourceAvailable_(route, sink,' + 26 computed: 'computeChangeRouteSourceAvailable_(route, sink,' +
27 'isAnySinkCurrentlyLaunching, shownCastModeValue)', 27 'isAnySinkCurrentlyLaunching, shownCastModeValue)',
28 }, 28 },
29 29
30 /** 30 /**
31 * The current time displayed in milliseconds.
32 * @type {number}
33 */
34 displayedCurrentTime_: {
35 type: Number,
36 value: 0
37 },
38
39 /**
40 * Whether updates for the current time from the browser should be ignored.
41 * Set to true when the user is dragging the time slider.
42 * @private {boolean}
43 */
44 ignoreExternalTimeUpdates_: {
45 type: Boolean,
46 value: false
47 },
48
49 /**
50 * Whether volume updates from the browser should be ignored. Set to true
51 * when the user is dragging the volume slider.
52 * @private {boolean}
53 */
54 ignoreExternalVolumeUpdates_: {
55 type: Boolean,
56 value: false
57 },
58
59 /**
31 * Whether a sink is currently launching in the container. 60 * Whether a sink is currently launching in the container.
32 * @type {boolean} 61 * @type {boolean}
33 */ 62 */
34 isAnySinkCurrentlyLaunching: { 63 isAnySinkCurrentlyLaunching: {
35 type: Boolean, 64 type: Boolean,
36 value: false, 65 value: false,
37 }, 66 },
38 67
39 /** 68 /**
40 * The route to show. 69 * The route to show.
41 * @type {?media_router.Route|undefined} 70 * @type {?media_router.Route|undefined}
42 */ 71 */
43 route: { 72 route: {
44 type: Object, 73 type: Object,
45 observer: 'maybeLoadCustomController_', 74 },
75
76
77 /**
78 * The status of the media route shown.
79 * @type {?media_router.RouteStatus}
80 */
81 routeStatus: {
82 type: Object,
83 observer: 'onRouteStatusChange_',
84 value: null
46 }, 85 },
47 86
48 /** 87 /**
49 * The cast mode shown to the user. Initially set to auto mode. (See 88 * The cast mode shown to the user. Initially set to auto mode. (See
50 * media_router.CastMode documentation for details on auto mode.) 89 * media_router.CastMode documentation for details on auto mode.)
51 * @type {number} 90 * @type {number}
52 */ 91 */
53 shownCastModeValue: { 92 shownCastModeValue: {
54 type: Number, 93 type: Number,
55 value: media_router.AUTO_CAST_MODE.type, 94 value: media_router.AUTO_CAST_MODE.type,
56 }, 95 },
57 96
58 /** 97 /**
59 * Sink associated with |route|. 98 * Sink associated with |route|.
60 * @type {?media_router.Sink} 99 * @type {?media_router.Sink}
61 */ 100 */
62 sink: { 101 sink: {
63 type: Object, 102 type: Object,
64 value: null, 103 value: null,
65 }, 104 },
66 105
67 /** 106 /**
68 * Whether the custom controller should be hidden. 107 * The value of the time slider, between 0 and 100.
69 * A custom controller is shown iff |route| specifies customControllerPath 108 * @type {number}
70 * and the view can be loaded.
71 * @private {boolean}
72 */ 109 */
73 isCustomControllerHidden_: { 110 timeSliderValue_: {
74 type: Boolean, 111 type: Number,
75 value: true, 112 value: 0
113 },
114
115 /**
116 * The value of the volume slider, between 0 and 100.
117 * @type {number}
118 */
119 volumeSliderValue_: {
120 type: Number,
121 value: 0
76 }, 122 },
77 }, 123 },
78 124
79 behaviors: [ 125 behaviors: [
80 I18nBehavior, 126 I18nBehavior,
81 ], 127 ],
82 128
83 /** 129 /**
84 * Fires a close-route event. This is called when the button to close 130 * Fires a close-route event. This is called when the button to close
85 * the current route is clicked. 131 * the current route is clicked.
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
148 if (!sink) { 194 if (!sink) {
149 return 0; 195 return 0;
150 } 196 }
151 if (castMode == media_router.CastModeType.AUTO) { 197 if (castMode == media_router.CastModeType.AUTO) {
152 return sink.castModes & -sink.castModes; 198 return sink.castModes & -sink.castModes;
153 } 199 }
154 return castMode & sink.castModes; 200 return castMode & sink.castModes;
155 }, 201 },
156 202
157 /** 203 /**
204 * @param {number} seekPosition The seek position in milliseconds.
205 * @param {number} duration The duration in milliseconds.
206 * @return {number} The seek position as a percentage between 0 and 100.
207 *
208 * @private
209 */
210 getSeekPositionPercentage_: function(seekPosition, duration) {
211 return duration ? (seekPosition / duration * 100) : 0;
212 },
213
214 /**
215 * @param {number} seekPositionPercentage Must be between 0 and 100.
216 * @param {number} duration The duration in milliseconds.
217 * @return {number} The seek position in milliseconds.
218 *
219 * @private
220 */
221 getSeekPosition_: function(seekPositionPercentage, duration) {
222 return duration ? (seekPositionPercentage * duration / 100) : 0;
223 },
224
225 /**
226 * Gets the duration formatted in HH:MM:SS format.
227 * @param {?media_router.RouteStatus} routeStatus
228 * @return {string}
229 *
230 * @private
231 */
232 getDuration_: function(routeStatus) {
233 return routeStatus ? this.getFormattedTime_(routeStatus.duration) : '';
234 },
235
236 /**
237 * Converts a number representing an interval of milliseconds to a string with
238 * HH:MM:SS format.
239 * @param {number} timeInMilliSec Must be positive. Intervals longer than 100
240 * hours get truncated silently.
241 * @return {string}
242 *
243 * @private
244 */
245 getFormattedTime_: function(timeInMilliSec) {
246 if (timeInMilliSec < 0) {
247 return '';
248 }
249 var hours = Math.floor(timeInMilliSec / 3600 / 1000);
250 var minutes = Math.floor(timeInMilliSec / 60 / 1000) % 60;
251 var seconds = Math.floor(timeInMilliSec / 1000) % 60;
252 var timeParts = [
253 ('0' + hours).substr(-2), ('0' + minutes).substr(-2),
254 ('0' + seconds).substr(-2)
255 ];
256 return timeParts.join(':');
257 },
258
259 /**
260 * @param {?media_router.RouteStatus} routeStatus
261 * @return {string} The value for the icon attribute of the mute/unmute
262 * button.
263 *
264 * @private
265 */
266 getMuteUnmuteIcon_: function(routeStatus) {
267 return (routeStatus && routeStatus.isMuted) ? 'av:volume-off' :
268 'av:volume-up';
269 },
270
271 /**
272 * @param {?media_router.RouteStatus} routeStatus
273 * @return {string} Localized title for the mute/unmute button.
274 *
275 * @private
276 */
277 getMuteUnmuteTitle_: function(routeStatus) {
278 return (routeStatus && routeStatus.isMuted) ? this.i18n('unmuteTitle') :
279 this.i18n('muteTitle');
280 },
281
282 /**
283 * @param {?media_router.RouteStatus} routeStatus
284 * @return {string}The value for the icon attribute of the play/pause button.
285 *
286 * @private
287 */
288 getPlayPauseIcon_: function(routeStatus) {
289 return (routeStatus && routeStatus.isPaused) ? 'av:play-arrow' : 'av:pause';
290 },
291
292 /**
293 * @param {?media_router.RouteStatus} routeStatus
294 * @return {string} Localized title for the play/pause button.
295 *
296 * @private
297 */
298 getPlayPauseTitle_: function(routeStatus) {
299 return (routeStatus && routeStatus.isPaused) ? this.i18n('playTitle') :
300 this.i18n('pauseTitle');
301 },
302
303 /**
304 * Sends a play or pause command to the browser.
305 *
306 * @private
307 */
308 onPlayPause_: function() {
309 if (this.routeStatus.isPaused) {
310 this.fire('play-route');
311 } else {
312 this.fire('pause-route');
313 }
314 },
315
316 /**
317 * Sends a mute or unmute command to the browser.
318 *
319 * @private
320 */
321 onMuteUnmute_: function() {
322 this.fire('set-route-mute', {mute: !this.routeStatus.isMuted});
323 },
324
325 /**
326 * Updates seek and volume sliders if the user is not currently dragging on
327 * them.
328 * @param {?media_router.RouteStatus} newRouteStatus
329 * @param {?media_router.RouteStatus} oldRouteStatus
330 *
331 * @private
332 */
333 onRouteStatusChange_: function(newRouteStatus, oldRouteStatus) {
334 if (!newRouteStatus)
335 return;
336
337 if (!this.ignoreExternalTimeUpdates_) {
338 this.displayedCurrentTime_ = newRouteStatus.currentTime;
339 this.timeSliderValue_ = this.getSeekPositionPercentage_(
340 newRouteStatus.currentTime, newRouteStatus.duration);
341 }
342
343 if (!this.ignoreExternalVolumeUpdates_) {
344 this.volumeSliderValue_ = newRouteStatus.volume;
345 }
346 },
347
348 /**
349 * Called when the user starts dragging the current-time slider.
350 * @param {!Event} e
351 *
352 * @private
353 */
354 onImmediateTimeSliderChange_: function(e) {
355 this.ignoreExternalTimeUpdates_ = true;
356 /** @type {{immediateValue: number}} */
357 var target = e.target;
358 this.timeSliderValue_ = target.immediateValue;
359 this.displayedCurrentTime_ = this.getSeekPosition_(
360 this.timeSliderValue_, this.routeStatus.duration);
361 },
362
363 /**
364 * Called when the user clicks on or stops dragging the current-time slider.
365 * @param {!Event} e
366 *
367 * @private
368 */
369 onTimeSliderChange_: function(e) {
370 this.ignoreExternalTimeUpdates_ = false;
371 /** @type {{value: number}} */
372 var target = e.target;
373 this.timeSliderValue_ = target.value;
374 this.displayedCurrentTime_ = this.getSeekPosition_(
375 this.timeSliderValue_, this.routeStatus.duration);
376 this.fire('seek-route', {time: this.displayedCurrentTime_});
377 },
378
379 /**
380 * Called when the user starts dragging the volume slider.
381 * @param {!Event} e
382 *
383 * @private
384 */
385 onImmediateVolumeSliderChange_: function(e) {
386 this.ignoreExternalVolumeUpdates_ = true;
387 /** @type {{immediateValue: number}} */
388 var target = e.target;
389 this.volumeSliderValue_ = target.immediateValue;
390 },
391
392 /**
393 * Called when the user clicks on or stops dragging the volume slider.
394 * @param {!Event} e
395 *
396 * @private
397 */
398 onVolumeSliderChange_: function(e) {
399 this.ignoreExternalVolumeUpdates_ = false;
400 /** @type {{value: number}} */
401 var target = e.target;
402 this.volumeSliderValue_ = target.value;
403 this.fire('set-route-volume', {volume: this.volumeSliderValue_});
404 },
405
406 /**
158 * Fires a join-route-click event if the current route is joinable, otherwise 407 * Fires a join-route-click event if the current route is joinable, otherwise
159 * it fires a change-route-source-click event, which changes the source of the 408 * it fires a change-route-source-click event, which changes the source of the
160 * current route. This may cause the current route to be closed and a new 409 * current route. This may cause the current route to be closed and a new
161 * route to be started. This is called when the button to start casting to the 410 * route to be started. This is called when the button to start casting to the
162 * current route is clicked. 411 * current route is clicked.
163 * 412 *
164 * @private 413 * @private
165 */ 414 */
166 startCastingToRoute_: function() { 415 startCastingToRoute_: function() {
167 if (this.route.canJoin) { 416 if (this.route.canJoin) {
168 this.fire('join-route-click', {route: this.route}); 417 this.fire('join-route-click', {route: this.route});
169 } else { 418 } else {
170 this.fire('change-route-source-click', { 419 this.fire('change-route-source-click', {
171 route: this.route, 420 route: this.route,
172 selectedCastMode: 421 selectedCastMode:
173 this.computeSelectedCastMode_(this.shownCastModeValue, this.sink) 422 this.computeSelectedCastMode_(this.shownCastModeValue, this.sink)
174 }); 423 });
175 } 424 }
176 }, 425 },
177
178 /**
179 * Loads the custom controller if |route.customControllerPath| exists.
180 * Falls back to the default route details view otherwise, or if load fails.
181 * Updates |activityStatus_| for the default view.
182 *
183 * @private
184 */
185 maybeLoadCustomController_: function() {
186 this.activityStatus_ = this.route ?
187 loadTimeData.getStringF('castingActivityStatus',
188 this.route.description) :
189 '';
190
191 if (!this.route || !this.route.customControllerPath) {
192 this.isCustomControllerHidden_ = true;
193 return;
194 }
195
196 // Show custom controller
197 var extensionview = this.$['custom-controller'];
198
199 // Do nothing if the url is the same and the view is not hidden.
200 if (this.route.customControllerPath == extensionview.src &&
201 !this.isCustomControllerHidden_)
202 return;
203
204 var that = this;
205 extensionview.load(this.route.customControllerPath)
206 .then(function() {
207 // Load was successful; show the custom controller.
208 that.isCustomControllerHidden_ = false;
209 }, function() {
210 // Load was unsuccessful; fall back to default view.
211 that.isCustomControllerHidden_ = true;
212 });
213 },
214 }); 426 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698