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

Unified Diff: chrome/browser/resources/media_router/elements/route_controls/route_controls.js

Issue 2725503002: [Media Router] Custom Controls 4 - Implement details view WebUI (Closed)
Patch Set: Fix a test Created 3 years, 8 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/resources/media_router/elements/route_controls/route_controls.js
diff --git a/chrome/browser/resources/media_router/elements/route_controls/route_controls.js b/chrome/browser/resources/media_router/elements/route_controls/route_controls.js
new file mode 100644
index 0000000000000000000000000000000000000000..f53a41a5dcd7cf96ee0a7940c7015226e7847141
--- /dev/null
+++ b/chrome/browser/resources/media_router/elements/route_controls/route_controls.js
@@ -0,0 +1,345 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This Polymer element shows media controls for a route that is currently cast
+// to a device.
+Polymer({
+ is: 'route-controls',
+
+ properties: {
+ /**
+ * The current time displayed in seconds.
+ * @type {number}
+ */
+ displayedCurrentTime_: {
+ type: Number,
+ value: 0
+ },
+
+ /**
+ * Whether updates for the current time from the browser should be ignored.
+ * Set to true when the user is dragging the time slider.
+ * @private {boolean}
+ */
+ 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.
+ type: Boolean,
+ value: false
+ },
+
+ /**
+ * Whether volume updates from the browser should be ignored. Set to true
+ * when the user is dragging the volume slider.
+ * @private {boolean}
+ */
+ ignoreExternalVolumeUpdates_: {
mark a. foltz 2017/05/03 21:27:00 isVolumeChanging_
takumif 2017/05/05 18:57:40 Done.
+ type: Boolean,
+ value: false
+ },
+
+ /**
+ * Whether we have received status updates from the browser for the current
+ * route. When this is false, we allow updating the media title based on the
+ * 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
+ * @private {boolean}
+ */
+ receivedStatusUpdates_: {
+ type: Boolean,
+ value: false
+ },
+
+ /**
+ * The route to show.
+ * @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.
+ */
+ route: {
+ type: Object,
+ observer: 'onRouteChange_',
+ value: null
+ },
+
+ /**
+ * The status of the media route shown. External updates are done using
+ * 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
+ * @private {?media_router.RouteStatus}
+ */
+ routeStatus_: {
+ type: Object,
+ observer: 'onRouteStatusChange_',
+ value: null
+ },
+
+ /**
+ * 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
+ * @type {number}
+ */
+ timeSliderValue_: {
mark a. foltz 2017/05/03 21:26:59 currentTimeFraction_ ?
takumif 2017/05/05 18:57:39 Merged with displayedCurrentTime_
+ type: Number,
+ value: 0
+ },
+
+ /**
+ * 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.
+ * @type {number}
+ */
+ volumeSliderValue_: {
+ type: Number,
+ value: 0
+ },
+ },
+
+ behaviors: [
+ I18nBehavior,
+ ],
+
+ /**
+ * Gets the duration formatted in HH:MM:SS format.
+ * @param {?media_router.RouteStatus} routeStatus
+ * @return {string}
+ *
+ * @private
+ */
+ getDuration_: function(routeStatus) {
+ return routeStatus ? this.getFormattedTime_(routeStatus.duration) : '';
+ },
+
+ /**
+ * Converts a number representing an interval of seconds to a string with
+ * HH:MM:SS format.
+ * @param {number} timeInSec Must be non-negative. Intervals longer than 100
+ * hours get truncated silently.
+ * @return {string}
+ *
+ * @private
+ */
+ getFormattedTime_: function(timeInSec) {
+ if (timeInSec < 0) {
+ return '';
+ }
+ 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
+ var minutes = Math.floor(timeInSec / 60) % 60;
+ var seconds = Math.floor(timeInSec) % 60;
+ var timeParts = [
+ ('0' + hours).substr(-2), ('0' + minutes).substr(-2),
+ ('0' + seconds).substr(-2)
+ ];
+ 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.
+ },
+
+ /**
+ * @param {?media_router.RouteStatus} routeStatus
+ * @return {string} The value for the icon attribute of the mute/unmute
+ * button.
+ *
+ * @private
+ */
+ getMuteUnmuteIcon_: function(routeStatus) {
+ 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.
+ 'av:volume-up';
+ },
+
+ /**
+ * @param {?media_router.RouteStatus} routeStatus
+ * @return {string} Localized title for the mute/unmute button.
+ *
+ * @private
+ */
+ getMuteUnmuteTitle_: function(routeStatus) {
+ return (routeStatus && routeStatus.isMuted) ? this.i18n('unmuteTitle') :
+ this.i18n('muteTitle');
+ },
+
+ /**
+ * @param {?media_router.RouteStatus} routeStatus
+ * @return {string}The value for the icon attribute of the play/pause button.
+ *
+ * @private
+ */
+ getPlayPauseIcon_: function(routeStatus) {
+ return (routeStatus && routeStatus.isPaused) ? 'av:play-arrow' : 'av:pause';
+ },
+
+ /**
+ * @param {?media_router.RouteStatus} routeStatus
+ * @return {string} Localized title for the play/pause button.
+ *
+ * @private
+ */
+ getPlayPauseTitle_: function(routeStatus) {
+ return (routeStatus && routeStatus.isPaused) ? this.i18n('playTitle') :
+ this.i18n('pauseTitle');
+ },
+
+ /**
+ * @param {number} seekPositionRatio The ratio with the duration, which must
+ * be between 0 and 1.
+ * @param {number} duration The duration in seconds.
+ * @return {number} The seek position in seconds.
+ *
+ * @private
+ */
+ 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
+ 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.
+ },
+
+ /**
+ * @param {number} seekPosition The seek position in seconds.
+ * @param {number} duration The duration in seconds.
+ * @return {number} The seek position as a ratio with the duration, between 0
+ * and 1.
+ *
+ * @private
+ */
+ getSeekPositionRatio_: function(seekPosition, duration) {
mark a. foltz 2017/05/03 21:27:00 getSeekPosition_(seekTime, duration) ?
takumif 2017/05/05 18:57:39 Removing.
+ return duration ? (seekPosition / duration) : 0;
+ },
+
+ /**
+ * Called when the user starts dragging the current-time slider.
+ * @param {!Event} e
+ *
+ * @private
+ */
+ onImmediateTimeSliderChange_: function(e) {
mark a. foltz 2017/05/03 21:26:59 onSeekStart_ ?
takumif 2017/05/05 18:57:39 Done.
+ this.ignoreExternalTimeUpdates_ = true;
+ /** @type {{immediateValue: number}} */
+ var target = e.target;
+ this.timeSliderValue_ = target.immediateValue;
+ this.displayedCurrentTime_ = this.getSeekPosition_(
+ this.timeSliderValue_, this.routeStatus_.duration);
+ },
+
+ /**
+ * Called when the user starts dragging the volume slider.
+ * @param {!Event} e
+ *
+ * @private
+ */
+ onImmediateVolumeSliderChange_: function(e) {
mark a. foltz 2017/05/03 21:27:00 onVolumeChangeStart_?
takumif 2017/05/05 18:57:40 Done.
+ this.ignoreExternalVolumeUpdates_ = true;
+ /** @type {{immediateValue: number}} */
+ var target = e.target;
+ this.volumeSliderValue_ = target.immediateValue;
+ },
+
+ /**
+ * 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.
+ *
+ * @private
+ */
+ onMuteUnmute_: function() {
+ media_router.browserApi.setCurrentMediaMute(!this.routeStatus_.isMuted);
+ },
+
+ /**
+ * 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.
+ *
+ * @private
+ */
+ onPlayPause_: function() {
+ if (this.routeStatus_.isPaused) {
+ media_router.browserApi.playCurrentMedia();
+ } else {
+ media_router.browserApi.pauseCurrentMedia();
+ }
+ },
+
+ /**
+ * Updates the route title shown, if no status updates have been received.
+ *
+ * @private
+ */
+ onRouteChange_: function(newRoute) {
+ if (!newRoute || this.receivedStatusUpdates_)
+ return;
+
+ // Hide all the elements except for the title showing the route description.
+ 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
+ loadTimeData.getStringF('castingActivityStatus', newRoute.description),
+ '', false, false, false, false, false, false, 0, 0, 0);
+ },
+
+ /**
+ * Called when the route details view is closed.
+ */
+ onRouteDetailsClosed: function() {
+ this.receivedStatusUpdates_ = false;
+ this.routeStatus_ = null;
+ media_router.ui.setRouteControls(null);
+ },
+
+ /**
+ * Updates seek and volume sliders if the user is not currently dragging on
+ * them.
+ * @param {?media_router.RouteStatus} newRouteStatus
+ *
+ * @private
+ */
+ onRouteStatusChange_: function(newRouteStatus) {
+ if (!newRouteStatus)
+ return;
+
+ if (!this.ignoreExternalTimeUpdates_) {
+ this.displayedCurrentTime_ = newRouteStatus.currentTime;
+ this.timeSliderValue_ = this.getSeekPositionRatio_(
+ newRouteStatus.currentTime, newRouteStatus.duration);
+ }
+
+ if (!this.ignoreExternalVolumeUpdates_) {
+ this.volumeSliderValue_ = newRouteStatus.volume;
+ }
+ },
+
+ /**
+ * Called when the user clicks on or stops dragging the current-time slider.
+ * @param {!Event} e
+ *
+ * @private
+ */
+ onTimeSliderChange_: function(e) {
mark a. foltz 2017/05/03 21:27:00 onSeekComplete_
takumif 2017/05/05 18:57:40 Done.
+ if (!this.routeStatus_)
+ return;
+
+ this.ignoreExternalTimeUpdates_ = false;
+ /** @type {{value: number}} */
+ var target = e.target;
+ this.timeSliderValue_ = target.value;
+ this.displayedCurrentTime_ = this.getSeekPosition_(
+ this.timeSliderValue_, this.routeStatus_.duration);
+ media_router.browserApi.seekCurrentMedia(this.displayedCurrentTime_);
+ },
+
+ /**
+ * Called when the user clicks on or stops dragging the volume slider.
+ * @param {!Event} e
+ *
+ * @private
+ */
+ onVolumeSliderChange_: function(e) {
mark a. foltz 2017/05/03 21:27:00 onVolumeChangeComplete_
takumif 2017/05/05 18:57:39 Done.
+ if (!this.routeStatus_)
+ return;
+
+ this.ignoreExternalVolumeUpdates_ = false;
+ /** @type {{value: number}} */
+ var target = e.target;
+ this.volumeSliderValue_ = target.value;
+ media_router.browserApi.setCurrentMediaVolume(this.volumeSliderValue_);
+ },
+
+ /**
+ * Called by Polymer on ready.
+ */
+ ready: function() {
+ media_router.ui.setRouteControls(this);
+ },
+
+ /**
+ * Updates the route status that is displayed on the controls.
+ *
+ * @param {!media_router.RouteStatus} status
+ */
+ updateRouteStatus: function(status) {
+ 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.
+ this.routeStatus_ = status;
+ },
+});

Powered by Google App Engine
This is Rietveld 408576698