Skip to content

Commit

Permalink
Converts Tabs related components into redux
Browse files Browse the repository at this point in the history
Resolves brave#8690

Fixes tab overrendering
  • Loading branch information
NejcZdovc committed May 19, 2017
1 parent 5fc6f05 commit 8fbf375
Show file tree
Hide file tree
Showing 14 changed files with 640 additions and 441 deletions.
145 changes: 145 additions & 0 deletions app/common/state/tabState.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ const windowState = require('./windowState')
// this file should eventually replace frameStateUtil
const frameStateUtil = require('../../../js/state/frameStateUtil')
const {isLocationBookmarked} = require('../../../js/state/siteUtil')
const locale = require('../../../js/l10n')
const getSetting = require('../../../js/settings').getSetting
const settings = require('../../../js/constants/settings.js')
const styles = require('../../renderer/components/styles/global')
const {hasBreakpoint} = require('../../renderer/lib/tabUtil')
const {getTextColorForBackground} = require('../../../js/lib/color')

const validateId = function (propName, id) {
assert.ok(id, `${propName} cannot be null`)
Expand Down Expand Up @@ -429,6 +435,145 @@ const tabState = {
state = tabState.removeTabField(state, 'frame')
state = state.delete('tabsInternal')
return state.delete('tabs')
},

getPageIndex: (windowState) => {
const tabPageIndex = windowState.getIn(['ui', 'tabs', 'tabPageIndex'])
const previewTabPageIndex = windowState.getIn(['ui', 'tabs', 'previewTabPageIndex'])

return previewTabPageIndex !== undefined
? previewTabPageIndex : tabPageIndex
},

getTabWindowProps: (windowState, frameKey) => {
return windowState.get('tabs').find((tab) => tab.get('frameKey') === frameKey) || makeImmutable({})
},

getThemeColor: (windowState, frameKey) => {
const tab = tabState.getTabWindowProps(windowState, frameKey)
return getSetting(settings.PAINT_TABS) && (tab.get('themeColor') || tab.get('computedThemeColor'))
},

canPlayAudio: (windowState, frameKey) => {
const tab = tabState.getTabWindowProps(windowState, frameKey)
return tab.get('audioPlaybackActive') || tab.get('audioMuted')
},

isTabLoading (windowState, frameKey) {
const tab = tabState.getTabWindowProps(windowState, frameKey)
return tab.size > 0 &&
(tab.get('loading') ||
tab.get('location') === 'about:blank') &&
(!tab.get('provisionalLocation') ||
!tab.get('provisionalLocation').startsWith('chrome-extension://mnojpmjdmbbfmejpflffifhffcmidifd/'))
},

isMediumView (windowState, frameKey) {
const tab = tabState.getTabWindowProps(windowState, frameKey)
const sizes = ['large', 'largeMedium']

return sizes.includes(tab.get('breakpoint'))
},

isNarrowView (windowState, frameKey) {
const tab = tabState.getTabWindowProps(windowState, frameKey)
const sizes = ['medium', 'mediumSmall', 'small', 'extraSmall', 'smallest']

return sizes.includes(tab.get('breakpoint'))
},

isNarrowestView (windowState, frameKey) {
const tab = tabState.getTabWindowProps(windowState, frameKey)
const sizes = ['extraSmall', 'smallest']

return sizes.includes(tab.get('breakpoint'))
},

getDisplayTitle (windowState, frameKey) {
const tab = tabState.getTabWindowProps(windowState, frameKey)

if (tab.size === 0) {
return ''
}

// For renderer initiated navigations, make sure we show Untitled
// until we know what we're loading. We should probably do this for
// all about: pages that we already know the title for so we don't have
// to wait for the title to be parsed.
if (tab.get('location') === 'about:blank') {
return locale.translation('aboutBlankTitle')
} else if (tab.get('location') === 'about:newtab') {
return locale.translation('newTab')
}

// YouTube tries to change the title to add a play icon when
// there is audio. Since we have our own audio indicator we get
// rid of it.
return (tab.get('title') || tab.get('location') || '').replace('▶ ', '')
},

getTabIconColor (windowState, frameKey) {
const tab = tabState.getTabWindowProps(windowState, frameKey)
const isActive = frameStateUtil.isFrameKeyActive(windowState, frameKey)

if (tab.size === 0) {
return ''
}

const themeColor = tab.get('themeColor') || tab.get('computedThemeColor')
const activeNonPrivateTab = !tab.get('isPrivate') && isActive
const isPrivateTab = tab.get('isPrivate') && (isActive || tab.get('hoverState'))
const defaultColor = isPrivateTab ? styles.color.white100 : styles.color.black100
const isPaintTabs = getSetting(settings.PAINT_TABS)

return activeNonPrivateTab && isPaintTabs && !!themeColor
? getTextColorForBackground(themeColor)
: defaultColor
},

/**
* Check whether or not closeTab icon is always visible (fixed) in tab
*/
hasFixedCloseIcon (windowState, frameKey) {
const tab = tabState.getTabWindowProps(windowState, frameKey)
const isActive = frameStateUtil.isFrameKeyActive(windowState, frameKey)

if (tab.size === 0) {
return false
}

return (
isActive &&
// larger sizes still have a relative closeIcon
!hasBreakpoint(tab.get('breakpoint'), ['default', 'large']) &&
// We don't resize closeIcon as we do with favicon so don't show it
!hasBreakpoint(tab.get('breakpoint'), 'smallest')
)
},

/**
* Check whether or not closeTab icon is relative to hover state
*/
hasRelativeCloseIcon (windowState, frameKey) {
const tab = tabState.getTabWindowProps(windowState, frameKey)

return tab.get('hoverState') && hasBreakpoint(tab.get('breakpoint'), ['default', 'large'])
},

/**
* Check whether or not private or newSession icon should be visible
*/
hasVisibleSecondaryIcon (windowState, frameKey) {
const tab = tabState.getTabWindowProps(windowState, frameKey)

return (
// Hide icon on hover
!tabState.hasRelativeCloseIcon(windowState, frameKey) &&
// If closeIcon is fixed then there's no room for another icon
!tabState.hasFixedCloseIcon(windowState, frameKey) &&
// completely hide it for small sizes
!hasBreakpoint(tab.get('breakpoint'), ['mediumSmall', 'small', 'extraSmall', 'smallest'])
)
}
}

Expand Down
43 changes: 18 additions & 25 deletions app/renderer/components/main/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ const shieldState = require('../../../common/state/shieldState')
const siteSettingsState = require('../../../common/state/siteSettingsState')
const menuBarState = require('../../../common/state/menuBarState')
const windowState = require('../../../common/state/windowState.js')
const windowStore = require('../stores/windowStore')

// Util
const _ = require('underscore')
Expand All @@ -84,7 +85,6 @@ class Main extends ImmutableComponent {
this.onHideNoScript = this.onHideNoScript.bind(this)
this.onHideReleaseNotes = this.onHideReleaseNotes.bind(this)
this.onHideCheckDefaultBrowserDialog = this.onHideCheckDefaultBrowserDialog.bind(this)
this.onHamburgerMenu = this.onHamburgerMenu.bind(this)
this.onTabContextMenu = this.onTabContextMenu.bind(this)
this.onFind = this.onFind.bind(this)
this.onFindHide = this.onFindHide.bind(this)
Expand Down Expand Up @@ -503,6 +503,22 @@ class Main extends ImmutableComponent {
self.resetAltMenuProcessing()
windowActions.onBlur(getCurrentWindowId())
}

windowStore.addChangeListener(function () {
const paymentsEnabled = getSetting(settings.PAYMENTS_ENABLED)
if (paymentsEnabled) {
const windowState = self.props.windowState
const tabs = windowState && windowState.get('tabs')
if (tabs) {
try {
const presentP = tabs.some((tab) => {
return tab.get('location') === 'about:preferences#payments'
})
ipc.send(messages.LEDGER_PAYMENTS_PRESENT, presentP)
} catch (ex) { }
}
}
})
}

checkForTitleMode () {
Expand All @@ -527,11 +543,6 @@ class Main extends ImmutableComponent {
}
}

onHamburgerMenu (e) {
const activeFrame = frameStateUtil.getActiveFrame(this.props.windowState)
contextMenus.onHamburgerMenu((activeFrame && activeFrame.get('location')) || '', e)
}

onHideSiteInfo () {
windowActions.setSiteInfoVisible(false)
}
Expand Down Expand Up @@ -695,7 +706,6 @@ class Main extends ImmutableComponent {

const notifications = this.props.appState.get('notifications')
const hasNotifications = notifications && notifications.size
const notificationBarOrigin = notifications.map(bar => bar.get('frameOrigin'))

return <div id='window'
className={cx({
Expand Down Expand Up @@ -848,25 +858,8 @@ class Main extends ImmutableComponent {
}
</div>
<TabsToolbar
paintTabs={getSetting(settings.PAINT_TABS)}
shouldAllowWindowDrag={shouldAllowWindowDrag}
dragData={this.props.appState.getIn(['dragData', 'type']) === dragTypes.TAB && this.props.appState.get('dragData')}
previewTabs={getSetting(settings.SHOW_TAB_PREVIEWS)}
tabsPerTabPage={tabsPerPage}
tabPageIndex={this.props.windowState.getIn(['ui', 'tabs', 'tabPageIndex'])}
previewTabPageIndex={this.props.windowState.getIn(['ui', 'tabs', 'previewTabPageIndex'])}
fixTabWidth={this.props.windowState.getIn(['ui', 'tabs', 'fixTabWidth'])}
frames={this.props.windowState.get('frames')}
sites={appStateSites}
key='tab-bar'
activeFrameKey={(activeFrame && activeFrame.get('key')) || undefined}
onMenu={this.onHamburgerMenu}
notificationBarActive={notificationBarOrigin}
hasTabInFullScreen={
sortedFrames
.map((frame) => frame.get('isFullScreen'))
.some(fullScreenMode => fullScreenMode === true)
}
shouldAllowWindowDrag={shouldAllowWindowDrag}
/>
{
hasNotifications && activeFrame
Expand Down
62 changes: 42 additions & 20 deletions app/renderer/components/tabs/content/audioTabIcon.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,44 +6,66 @@ const React = require('react')
const {StyleSheet, css} = require('aphrodite/no-important')

// Components
const ImmutableComponent = require('../../immutableComponent')
const ReduxComponent = require('../../reduxComponent')
const TabIcon = require('./tabIcon')

// State
const tabState = require('../../../../common/state/tabState.js')

// Actions
const windowActions = require('../../../../../js/actions/windowActions.js')

// Utils
const frameStateUtil = require('../../../../../js/state/frameStateUtil.js')

// Styles
const globalStyles = require('../../styles/global')
const tabStyles = require('../../styles/tab')

class AudioTabIcon extends ImmutableComponent {
get pageCanPlayAudio () {
return !!this.props.frame.get('audioPlaybackActive')
class AudioTabIcon extends React.Component {
constructor () {
super()
this.toggleMute = this.toggleMute.bind(this)
}

get shouldShowAudioIcon () {
// We switch to blue top bar for all breakpoints but default
return this.props.frame.get('breakpoint') === 'default'
get audioIcon () {
const isMuted = this.props.pageCanPlayAudio && !this.props.audioMuted

return isMuted
? globalStyles.appIcons.volumeOn
: globalStyles.appIcons.volumeOff
}

get mutedState () {
return this.pageCanPlayAudio && !!this.props.frame.get('audioMuted')
toggleMute (event) {
event.stopPropagation()
windowActions.setAudioMuted(this.props.frameKey, this.props.tabId, !this.props.audioMuted)
}

get audioIcon () {
return !this.mutedState
? globalStyles.appIcons.volumeOn
: globalStyles.appIcons.volumeOff
mergeProps (state, dispatchProps, ownProps) {
const currentWindow = state.get('currentWindow')
const tab = tabState.getTabWindowProps(currentWindow, ownProps.frameKey)
const frame = frameStateUtil.getFrameByKey(currentWindow, ownProps.frameKey)

const props = {}
// used in renderer

// used in other functions
props.pageCanPlayAudio = !!tab.get('audioPlaybackActive')
props.tabId = frame ? frame.get('tabId') : tabState.TAB_ID_NONE
props.audioMuted = tab.get('audioMuted')

return Object.assign({}, ownProps, props)
}

render () {
return this.pageCanPlayAudio && this.shouldShowAudioIcon
? <TabIcon
className={css(tabStyles.icon, styles.audioIcon)}
symbol={this.audioIcon}
onClick={this.props.onClick} />
: null
return <TabIcon
className={css(tabStyles.icon, styles.audioIcon)}
symbol={this.audioIcon}
onClick={this.toggleMute} />
}
}

module.exports = AudioTabIcon
module.exports = ReduxComponent.connect(AudioTabIcon)

const styles = StyleSheet.create({
audioIcon: {
Expand Down
Loading

0 comments on commit 8fbf375

Please sign in to comment.