Skip to content
This repository has been archived by the owner on Dec 11, 2019. It is now read-only.

Add audio indicators and mute tab functionality #70

Merged
merged 2 commits into from
Dec 20, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/applicationState.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ Child components should not modify top level state directly, instead they should
{
activeFrameKey: number,
frames: [{
audioMuted: boolean, // frame is muted
audioPlaybackActive: boolean, // frame is playing audio
canGoBack: boolean,
canGoForward: boolean,
icon: string, // url to favicon
Expand Down
102 changes: 65 additions & 37 deletions js/actions/appActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const AppActions = {
* In general, an iframe's src should not be updated when navigating within the frame to a new page,
* but the location should. For user entered new URLs, both should be updated.
*
* @param location The URL of the page to load
* @param {string} location - The URL of the page to load
*/
loadUrl: function (location) {
if (UrlUtil.isURL(location)) {
Expand All @@ -37,8 +37,8 @@ const AppActions = {
* This differs from the above in that it will not change the webview's (iframe's) src.
* This should be used for inter-page navigation but not user initiated loads.
*
* @param location The URL of the page to load
* @param key The frame key to modify, it is checked against the active frame and if
* @param {string} location - The URL of the page to load
* @param {string} key - The frame key to modify, it is checked against the active frame and if
* it is active the URL text will also be changed.
*/
setLocation: function (location, key) {
Expand All @@ -56,7 +56,7 @@ const AppActions = {
* Dispatches a message to the store to set the user entered text for the URL bar.
* Unlike setLocation and loadUrl, this does not modify the state of src and location.
*
* @param location The text to set as the new navbar URL input
* @param {string} location - The text to set as the new navbar URL input
*/
setNavBarUserInput: function (location) {
AppDispatcher.dispatch({
Expand All @@ -69,8 +69,8 @@ const AppActions = {
* Dispatches a message to the store to set the current frame's title.
* This should be called in response to the webview encountering a <title> tag.
*
* @param frameProps The frame properties to modify
* @param title The title to set for the frame
* @param {Object} frameProps - The frame properties to modify
* @param {string} title - The title to set for the frame
*/
setFrameTitle: function (frameProps, title) {
AppDispatcher.dispatch({
Expand All @@ -83,7 +83,7 @@ const AppActions = {
/**
* Dispatches a message to the store to indicate that the webview is loading.
*
* @param frameProps The frame properties for the webview in question.
* @param {Object} frameProps - The frame properties for the webview in question.
*/
onWebviewLoadStart: function (frameProps) {
AppDispatcher.dispatch({
Expand All @@ -95,7 +95,7 @@ const AppActions = {
/**
* Dispatches a message to the store to indicate that the webview is done loading.
*
* @param frameProps The frame properties for the webview in question.
* @param {Object} frameProps - The frame properties for the webview in question.
*/
onWebviewLoadEnd: function (frameProps) {
AppDispatcher.dispatch({
Expand All @@ -107,7 +107,7 @@ const AppActions = {
/**
* Dispatches a message to the store to indicate if the navigation bar is focused.
*
* @param focused true if the navigation bar should be considered as focused
* @param {boolean} focused - true if the navigation bar should be considered as focused
*/
setNavBarFocused: function (focused) {
AppDispatcher.dispatch({
Expand All @@ -119,9 +119,9 @@ const AppActions = {
/**
* Dispatches a message to the store to create a new frame
*
* @param frameOpts An object of frame options such as isPrivate, element, and tab features.
* @param {Object} frameOpts - An object of frame options such as isPrivate, element, and tab features.
* These may not all be hooked up in Electron yet.
* @param openInForeground true if the new frame should become the new active frame
* @param {boolean} openInForeground - true if the new frame should become the new active frame
*/
newFrame: function (frameOpts = {}, openInForeground = true) {
frameOpts.location = frameOpts.location || Config.defaultUrl
Expand Down Expand Up @@ -185,7 +185,7 @@ const AppActions = {
/**
* Dispatches a message to the store to set a new frame as the active frame.
*
* @param frameProps the frame properties for the webview in question.
* @param {Object} frameProps - the frame properties for the webview in question.
*/
setActiveFrame: function (frameProps) {
if (!frameProps) {
Expand All @@ -200,7 +200,7 @@ const AppActions = {
/**
* Dispatches a message to the store to set the tab page index.
*
* @param index the tab page index to change to
* @param {number} index - the tab page index to change to
*/
setTabPageIndex: function (index) {
AppDispatcher.dispatch({
Expand All @@ -212,9 +212,9 @@ const AppActions = {
/**
* Dispatches a message to the store to update the back-forward information.
*
* @param frameProps the frame properties for the webview in question.
* @param canGoBack Specifies if the active frame has previous entries in its history
* @param canGoForward Specifies if the active frame has next entries in its history (i.e. the user pressed back at least once)
* @param {Object} frameProps - the frame properties for the webview in question.
* @param {boolean} canGoBack - Specifies if the active frame has previous entries in its history
* @param {boolean} canGoForward - Specifies if the active frame has next entries in its history (i.e. the user pressed back at least once)
*/
updateBackForwardState: function (frameProps, canGoBack, canGoForward) {
AppDispatcher.dispatch({
Expand All @@ -228,7 +228,7 @@ const AppActions = {
/**
* Dispatches a message to the store to indicate that tab dragging has started for that frame.
*
* @param frameProps the frame properties for the webview in question.
* @param {Object} frameProps - the frame properties for the webview in question.
*/
tabDragStart: function (frameProps) {
AppDispatcher.dispatch({
Expand All @@ -240,7 +240,7 @@ const AppActions = {
/**
* Dispatches a message to the store to indicate that tab dragging has stopped for that frame.
*
* @param frameProps the frame properties for the webview in question.
* @param {Object} frameProps - the frame properties for the webview in question.
*/
tabDragStop: function (frameProps) {
AppDispatcher.dispatch({
Expand All @@ -252,7 +252,7 @@ const AppActions = {
/**
* Dispatches a message to the store to indicate that something is dragging over the left half of this tab.
*
* @param frameProps the frame properties for the webview in question.
* @param {Object} frameProps - the frame properties for the webview in question.
*/
tabDragDraggingOverLeftHalf: function (frameProps) {
AppDispatcher.dispatch({
Expand All @@ -264,7 +264,7 @@ const AppActions = {
/**
* Dispatches a message to the store to indicate that something is dragging over the right half of this tab.
*
* @param frameProps the frame properties for the webview in question.
* @param {Object} frameProps - the frame properties for the webview in question.
*/
tabDragDraggingOverRightHalf: function (frameProps) {
AppDispatcher.dispatch({
Expand All @@ -276,7 +276,7 @@ const AppActions = {
/**
* Dispatches a message to the store to indicate that tab dragging has exited the frame
*
* @param frameProps the frame properties for the webview in question.
* @param {Object} frameProps - the frame properties for the webview in question.
*/
tabDragExit: function (frameProps) {
AppDispatcher.dispatch({
Expand All @@ -288,7 +288,7 @@ const AppActions = {
/**
* Dispatches a message to the store to indicate that tab dragging has exited the right half of the frame
*
* @param frameProps the frame properties for the webview in question.
* @param {Object} frameProps - the frame properties for the webview in question.
*/
tabDragExitRightHalf: function (frameProps) {
AppDispatcher.dispatch({
Expand All @@ -300,7 +300,7 @@ const AppActions = {
/**
* Dispatches a message to the store to indicate that tab dragging started on the tab
*
* @param frameProps the frame properties for the webview in question.
* @param {Object} frameProps - the frame properties for the webview in question.
*/
tabDraggingOn: function (frameProps) {
AppDispatcher.dispatch({
Expand All @@ -312,9 +312,9 @@ const AppActions = {
/**
* Dispatches a message to the store to indicate that the specified frame should move locations.
*
* @param sourceFrameProps the frame properties for the webview to move.
* @param destinationFrameProps the frame properties for the webview to move to.
* @param prepend Whether or not to prepend to the destinationFrameProps
* @param {Object} sourceFrameProps - the frame properties for the webview to move.
* @param {Object} destinationFrameProps - the frame properties for the webview to move to.
* @param {boolean} prepend - Whether or not to prepend to the destinationFrameProps
*/
moveTab: function (sourceFrameProps, destinationFrameProps, prepend) {
AppDispatcher.dispatch({
Expand All @@ -325,11 +325,11 @@ const AppActions = {
})
},

/*
/**
* Sets the URL bar suggestions and selected index.
*
* @param suggestionList The list of suggestions for the entered URL bar text. This can be generated from history, bookmarks, etc.
* @param selectedIndex The index for the selected item (users can select items with down arrow on their keyboard)
* @param {Object[]} suggestionList - The list of suggestions for the entered URL bar text. This can be generated from history, bookmarks, etc.
* @param {number} selectedIndex - The index for the selected item (users can select items with down arrow on their keyboard)
*/
setUrlBarSuggestions: function (suggestionList, selectedIndex) {
AppDispatcher.dispatch({
Expand Down Expand Up @@ -369,7 +369,7 @@ const AppActions = {
/**
* Marks the URL bar text as selected or not
*
* @param isSelected Whether or not the URL bar should be autoselected
* @param {boolean} isSelected - Whether or not the URL bar should be autoselected
*/
setUrlBarAutoselected: function (isAutoselected) {
AppDispatcher.dispatch({
Expand All @@ -381,7 +381,7 @@ const AppActions = {
/**
* Marks the URL bar as active or not
*
* @param isActive Whether or not the URL bar should be marked as active
* @param {boolean} isActive - Whether or not the URL bar should be marked as active
*/
setUrlBarActive: function (isActive) {
AppDispatcher.dispatch({
Expand All @@ -393,7 +393,7 @@ const AppActions = {
/**
* Dispatches a message to the store to indicate that the pending frame shortcut info should be updated.
*
* @param activeShortcut The text for the new shortcut. Usually this is null to clear info which was previously
* @param {string} activeShortcut - The text for the new shortcut. Usually this is null to clear info which was previously
* set from an IPC call.
*/
setActiveFrameShortcut: function (activeShortcut) {
Expand All @@ -405,7 +405,7 @@ const AppActions = {

/**
* Dispatches a message to set the search engine details.
* @param searchDetail the search details
* @param {Object} searchDetail - the search details
*/
setSearchDetail: function (searchDetail) {
AppDispatcher.dispatch({
Expand All @@ -416,8 +416,8 @@ const AppActions = {

/**
* Adds a site to the site list
* @param frameProps the frameProps for the frame in to bookmark
* @param tag A tag to associate with the site. e.g. bookmarks.
* @param {Object} frameProps - Properties of the frame in question
* @param {string} tag - A tag to associate with the site. e.g. bookmarks.
*/
addSite: function (frameProps, tag) {
AppDispatcher.dispatch({
Expand All @@ -429,15 +429,43 @@ const AppActions = {

/**
* Removes a site from the site list
* @param frameProps the frameProps for the frame in to bookmark
* @param tag A tag to associate with the site. e.g. bookmarks.
* @param {Object} frameProps - Properties of the frame in question
* @param {string} tag - A tag to associate with the site. e.g. bookmarks.
*/
removeSite: function (frameProps, tag) {
AppDispatcher.dispatch({
actionType: AppConstants.APP_REMOVE_SITE,
frameProps,
tag
})
},

/**
* Dispatches a message to indicate that the frame should be muted
*
* @param {Object} frameProps - Properties of the frame in question
* @param {boolean} muted - true if the frame is muted
*/
setAudioMuted: function (frameProps, muted) {
AppDispatcher.dispatch({
actionType: AppConstants.APP_SET_AUDIO_MUTED,
frameProps,
muted
})
},

/**
* Dispatches a message to indicate that audio is playing
*
* @param {Object} frameProps - Properties of the frame in question
* @param {boolean} audioPlaybackActive - true if audio is playing in the frame
*/
setAudioPlaybackActive: function (frameProps, audioPlaybackActive) {
AppDispatcher.dispatch({
actionType: AppConstants.APP_SET_AUDIO_PLAYBACK_ACTIVE,
frameProps,
audioPlaybackActive
})
}
}

Expand Down
21 changes: 21 additions & 0 deletions js/components/frame.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,17 @@ class Frame extends ImmutableComponent {
this.webview.canGoBack(),
this.webview.canGoForward())
})
this.webview.addEventListener('media-started-playing', ({title}) => {
AppActions.setAudioPlaybackActive(this.props.frame, true)
})
this.webview.addEventListener('media-paused', ({title}) => {
AppActions.setAudioPlaybackActive(this.props.frame, false)
})
// Ensure we mute appropriately, the initial value could be set
// from persisted state.
if (this.props.frame.get('audioMuted')) {
this.webview.setAudioMuted(true)
}
}

insertAds (currentLocation) {
Expand All @@ -125,6 +136,16 @@ class Frame extends ImmutableComponent {
this.webview.goForward()
}

componentWillReceiveProps (nextProps) {
if (nextProps.frame.get('audioMuted') &&
this.props.frame.get('audioMuted') !== true) {
this.webview.setAudioMuted(true)
} else if (!nextProps.frame.get('audioMuted') &&
this.props.frame.get('audioMuted') === true) {
this.webview.setAudioMuted(false)
}
}

render () {
return <div
className={cx({
Expand Down
6 changes: 5 additions & 1 deletion js/components/tabs.js
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ class Tab extends ImmutableComponent {
AppActions.closeFrame(this.props.frameProps)
}

onMuteFrame (muted) {
AppActions.setAudioMuted(this.props.frameProps, muted)
}

render () {
const thumbnailWidth = 160
const thumbnailHeight = 100
Expand Down Expand Up @@ -139,7 +143,7 @@ class Tab extends ImmutableComponent {
!this.props.frameProps.get('audioMuted'),
'fa-volume-off': this.props.frameProps.get('audioMuted')
})}
onClick={this.props.frameProps.get('audioMuted') ? this.props.onUnmuteFrame : this.props.onMuteFrame} />
onClick={this.onMuteFrame.bind(this, !this.props.frameProps.get('audioMuted'))} />
}

return <div className='tabArea'
Expand Down
4 changes: 3 additions & 1 deletion js/constants/appConstants.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ const appConstants = {
APP_SET_URL_BAR_AUTOSELECTED: _,
APP_SET_SEARCH_DETAIL: _,
APP_ADD_SITE: _,
APP_REMOVE_SITE: _
APP_REMOVE_SITE: _,
APP_SET_AUDIO_MUTED: _,
APP_SET_AUDIO_PLAYBACK_ACTIVE: _
}

module.exports = mapValuesByKeys(appConstants)
8 changes: 8 additions & 0 deletions js/stores/appStore.js
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,14 @@ AppDispatcher.register((action) => {
appState = appState.set('sites', SiteUtil.removeSite(appState.get('sites'), action.frameProps, action.tag))
appStore.emitChange()
break
case AppConstants.APP_SET_AUDIO_MUTED:
appState = appState.setIn(['frames', FrameStateUtil.getFramePropsIndex(appState.get('frames'), action.frameProps), 'audioMuted'], action.muted)
appStore.emitChange()
break
case AppConstants.APP_SET_AUDIO_PLAYBACK_ACTIVE:
appState = appState.setIn(['frames', FrameStateUtil.getFramePropsIndex(appState.get('frames'), action.frameProps), 'audioPlaybackActive'], action.audioPlaybackActive)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

audioMuted and audioPlaybackActive should go in docs/applicationState.md.

appStore.emitChange()
break
default:
}
})
Expand Down
2 changes: 1 addition & 1 deletion less/tabs.less
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
vertical-align: middle;
}
.playIcon {
cursor: default;
cursor: pointer;
margin-right: 4px;
}

Expand Down