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 4, 2017
1 parent 33e3fca commit 01742ee
Show file tree
Hide file tree
Showing 14 changed files with 641 additions and 498 deletions.
150 changes: 150 additions & 0 deletions app/common/state/tabState.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@ const frameState = require('./frameState')
const windowState = require('./windowState')
// this file should eventually replace frameStateUtil
const frameStateUtil = require('../../../js/state/frameStateUtil')
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 @@ -363,6 +369,150 @@ const tabState = {
state = tabState.removeTabField(state, 'messageBoxDetail')
state = tabState.removeTabField(state, 'frame')
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'))
},

isPinned (windowState, frameKey) {
const tab = tabState.getTabWindowProps(windowState, frameKey)
return tab && !!tab.get('pinnedLocation')
},

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
61 changes: 42 additions & 19 deletions app/renderer/components/tabs/content/audioTabIcon.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,43 +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.tab.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.tab.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.tab.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
62 changes: 48 additions & 14 deletions app/renderer/components/tabs/content/closeTabIcon.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,68 @@ const React = require('react')
const {StyleSheet, css} = require('aphrodite/no-important')

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

// Utils
const {hasRelativeCloseIcon, hasFixedCloseIcon} = require('../../../lib/tabUtil')
// State
const tabState = require('../../../../common/state/tabState.js')

// Store
const windowStore = require('../../../../../js/stores/windowStore.js')

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

// Styles
const globalStyles = require('../../styles/global')
const closeTabHoverSvg = require('../../../../extensions/brave/img/tabs/close_btn_hover.svg')
const closeTabSvg = require('../../../../extensions/brave/img/tabs/close_btn_normal.svg')

class CloseTabIcon extends ImmutableComponent {
get isPinned () {
return !!this.props.tab.get('pinnedLocation')
class CloseTabIcon extends React.Component {
constructor () {
super()
this.onClick = this.onClick.bind(this)
}
get frame () {
return windowStore.getFrame(this.props.frameKey)
}

onClick (event) {
event.stopPropagation()
if (this.frame && !this.frame.isEmpty()) {
// const rect = this.tabNode.parentNode.getBoundingClientRect() TODO FIX IT
windowActions.onTabClosedWithMouse({
fixTabWidth: 200 // rect.width
})
windowActions.closeFrame(this.frame)
}
}

mergeProps (state, dispatchProps, ownProps) {
const currentWindow = state.get('currentWindow')
const isPinnedTab = tabState.isPinned(currentWindow, ownProps.frameKey)

const props = {}

props.showCloseIcon = !isPinnedTab &&
(
tabState.hasRelativeCloseIcon(currentWindow, ownProps.frameKey) ||
tabState.hasFixedCloseIcon(currentWindow, ownProps.frameKey)
)
return Object.assign({}, ownProps, props)
}

render () {
return !this.isPinned &&
(hasRelativeCloseIcon(this.props) || hasFixedCloseIcon(this.props))
? <TabIcon
data-test-id='closeTabIcon'
className={css(styles.closeTab)}
{...this.props} />
: null
return <TabIcon
data-test-id='closeTabIcon'
className={css(this.props.showCloseIcon && styles.closeTab)}
l10nId='closeTabButton'
onClick={this.onClick}
/>
}
}

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

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

0 comments on commit 01742ee

Please sign in to comment.