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

Commit

Permalink
Merge pull request #10691 from brave/tabs-observer
Browse files Browse the repository at this point in the history
improve tabs performance and UI with this one simple trick
  • Loading branch information
cezaraugusto committed Sep 21, 2017
1 parent 720f97d commit 472f152
Show file tree
Hide file tree
Showing 52 changed files with 3,103 additions and 1,846 deletions.
56 changes: 56 additions & 0 deletions app/common/state/tabContentState/audioState.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

// State helpers
const frameStateUtil = require('../../../../js/state/frameStateUtil')

// Utils
const {isEntryIntersected} = require('../../../../app/renderer/lib/observerUtil')

module.exports.canPlayAudio = (state, frameKey) => {
const frame = frameStateUtil.getFrameByKey(state, frameKey)

if (frame == null) {
return false
}

return frame.get('audioPlaybackActive') || frame.get('audioMuted')
}

module.exports.isAudioMuted = (state, frameKey) => {
const frame = frameStateUtil.getFrameByKey(state, frameKey)

if (frame == null) {
return false
}

const tabCanPlayAudio = module.exports.canPlayAudio(state, frameKey)
return tabCanPlayAudio && frame.get('audioMuted')
}

module.exports.showAudioIcon = (state, frameKey) => {
const frame = frameStateUtil.getFrameByKey(state, frameKey)

if (frame == null) {
return false
}

return (
!isEntryIntersected(state, 'tabs') &&
module.exports.canPlayAudio(state, frameKey)
)
}

module.exports.showAudioTopBorder = (state, frameKey, isPinned) => {
const frame = frameStateUtil.getFrameByKey(state, frameKey)

if (frame == null) {
return false
}

return (
module.exports.canPlayAudio(state, frameKey) &&
(isEntryIntersected(state, 'tabs') || isPinned)
)
}
52 changes: 52 additions & 0 deletions app/common/state/tabContentState/closeState.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

// State helpers
const frameStateUtil = require('../../../../js/state/frameStateUtil')

// Utils
const {isEntryIntersected} = require('../../../../app/renderer/lib/observerUtil')

// Styles
const {intersection} = require('../../../renderer/components/styles/global')

module.exports.hasFixedCloseIcon = (state, frameKey) => {
const frame = frameStateUtil.getFrameByKey(state, frameKey)

if (frame == null) {
return false
}

return (
frameStateUtil.isFrameKeyActive(state, frameKey) &&
isEntryIntersected(state, 'tabs', intersection.at75)
)
}

module.exports.hasRelativeCloseIcon = (state, frameKey) => {
const frame = frameStateUtil.getFrameByKey(state, frameKey)

if (frame == null) {
return false
}

return (
frameStateUtil.getTabHoverState(state, frameKey) &&
!isEntryIntersected(state, 'tabs', intersection.at75)
)
}

module.exports.showCloseTabIcon = (state, frameKey) => {
const frame = frameStateUtil.getFrameByKey(state, frameKey)

if (frame == null) {
return false
}

return !isEntryIntersected(state, 'tabs', intersection.at20) &&
(
module.exports.hasRelativeCloseIcon(state, frameKey) ||
module.exports.hasFixedCloseIcon(state, frameKey)
)
}
87 changes: 87 additions & 0 deletions app/common/state/tabContentState/faviconState.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

// Utils
const {isSourceAboutUrl} = require('../../../../js/lib/appUrlUtil')
const frameStateUtil = require('../../../../js/state/frameStateUtil')
const {isEntryIntersected} = require('../../../../app/renderer/lib/observerUtil')

// Styles
const {intersection} = require('../../../renderer/components/styles/global')

module.exports.showFavicon = (state, frameKey) => {
const frame = frameStateUtil.getFrameByKey(state, frameKey)

if (frame == null) {
return false
}

const isNewTabPage = frameStateUtil.frameLocationMatch(frame, 'about:newtab')

if (isEntryIntersected(state, 'tabs', intersection.at40)) {
// do not show it at all at minimum ratio (intersection.at12)
if (isEntryIntersected(state, 'tabs', intersection.at12)) {
return false
}

return (
// when almost all tab content is covered,
// only show favicon if there's no closeIcon (intersection.at20)
// or otherwise only for the non-active tab
isEntryIntersected(state, 'tabs', intersection.at20) ||
!frameStateUtil.isFrameKeyActive(state, frameKey)
)
}

// new tab page is the only tab we do not show favicon
return !isNewTabPage
}

module.exports.getFavicon = (state, frameKey) => {
const frame = frameStateUtil.getFrameByKey(state, frameKey)
const isLoadingVisible = module.exports.showLoadingIcon(state, frameKey)

if (frame == null) {
return ''
}

return !isLoadingVisible && frame.get('icon')
}

module.exports.showLoadingIcon = (state, frameKey) => {
const frame = frameStateUtil.getFrameByKey(state, frameKey)

if (frame == null) {
return false
}

if (frame.get('loading') == null) {
return false
}

return (
!isSourceAboutUrl(frame.get('location')) &&
frame.get('loading')
)
}

module.exports.showIconWithLessMargin = (state, frameKey) => {
const frame = frameStateUtil.getFrameByKey(state, frameKey)

if (frame == null) {
return false
}

return isEntryIntersected(state, 'tabs', intersection.at30)
}

module.exports.showFaviconAtReducedSize = (state, frameKey) => {
const frame = frameStateUtil.getFrameByKey(state, frameKey)

if (frame == null) {
return false
}

return isEntryIntersected(state, 'tabs', intersection.at20)
}
65 changes: 65 additions & 0 deletions app/common/state/tabContentState/partitionState.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

// State helpers
const tabUIState = require('../tabUIState')
const frameStateUtil = require('../../../../js/state/frameStateUtil')

// Constants
const {tabs} = require('../../../../js/constants/config')

module.exports.isPartitionTab = (state, frameKey) => {
const frame = frameStateUtil.getFrameByKey(state, frameKey)

if (frame == null) {
return false
}

return !!frame.get('partitionNumber')
}

module.exports.getPartitionNumber = (state, frameKey) => {
const frame = frameStateUtil.getFrameByKey(state, frameKey)

if (frame == null) {
return 0
}

const partitionNumber = frame.get('partitionNumber')
if (typeof partitionNumber === 'string') {
return partitionNumber.replace(/^partition-/i, '')
}
return partitionNumber
}

module.exports.getMaxAllowedPartitionNumber = (state, frameKey) => {
const frame = frameStateUtil.getFrameByKey(state, frameKey)

if (frame == null) {
return 0
}

const partitionNumber = module.exports.getPartitionNumber(state, frameKey)

if (partitionNumber > tabs.maxAllowedNewSessions) {
return tabs.maxAllowedNewSessions
}
return partitionNumber
}

module.exports.showPartitionIcon = (state, frameKey) => {
const frame = frameStateUtil.getFrameByKey(state, frameKey)

if (frame == null) {
if (process.env.NODE_ENV !== 'test') {
console.error('Unable to find frame for showPartitionIcon method')
}
return false
}

return (
module.exports.isPartitionTab(state, frameKey) &&
tabUIState.showTabEndIcon(state, frameKey)
)
}
30 changes: 30 additions & 0 deletions app/common/state/tabContentState/privateState.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

// State helpers
const tabUIState = require('../tabUIState')
const frameStateUtil = require('../../../../js/state/frameStateUtil')

module.exports.isPrivateTab = (state, frameKey) => {
const frame = frameStateUtil.getFrameByKey(state, frameKey)

if (frame == null) {
return false
}

return !!frame.get('isPrivate')
}

module.exports.showPrivateIcon = (state, frameKey) => {
const frame = frameStateUtil.getFrameByKey(state, frameKey)

if (frame == null) {
return false
}

return (
module.exports.isPrivateTab(state, frameKey) &&
tabUIState.showTabEndIcon(state, frameKey)
)
}
64 changes: 64 additions & 0 deletions app/common/state/tabContentState/titleState.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

const locale = require('../../../../js/l10n')

// State helpers
const partitionState = require('../tabContentState/partitionState')
const privateState = require('../tabContentState/privateState')
const frameStateUtil = require('../../../../js/state/frameStateUtil')

// Utils
const {isEntryIntersected} = require('../../../../app/renderer/lib/observerUtil')

// Styles
const {intersection} = require('../../../renderer/components/styles/global')

module.exports.showTabTitle = (state, frameKey) => {
const frame = frameStateUtil.getFrameByKey(state, frameKey)

if (frame == null) {
return false
}

const isNewTabPage = frameStateUtil.frameLocationMatch(frame, 'about:newtab')
const isActive = frameStateUtil.isFrameKeyActive(state, frameKey)
const isPartition = partitionState.isPartitionTab(state, frameKey)
const isPrivate = privateState.isPrivateTab(state, frameKey)
const secondaryIconVisible = !isNewTabPage && (isPartition || isPrivate || isActive)

// If title is being intersected by ~half with other icons visible
// such as closeTab (activeTab) or session icons, do not show it
if (isEntryIntersected(state, 'tabs', intersection.at45) && secondaryIconVisible) {
return false
}

// title should never show at such intersection point
return !isEntryIntersected(state, 'tabs', intersection.at40)
}

module.exports.getDisplayTitle = (state, frameKey) => {
const frame = frameStateUtil.getFrameByKey(state, frameKey)

if (frame == null) {
return ''
}

const isNewTabPage = frameStateUtil.frameLocationMatch(frame, 'about:newtab')
const isAboutBlankPage = frameStateUtil.frameLocationMatch(frame, 'about:blank')
// For renderer initiated navigation, 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 (isAboutBlankPage) {
return locale.translation('aboutBlankTitle')
} else if (isNewTabPage) {
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 (frame.get('title') || frame.get('location') || '').replace('▶ ', '')
}
Loading

0 comments on commit 472f152

Please sign in to comment.