diff --git a/BUILD.gn b/BUILD.gn
index 1fbb6c3..082aea2 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -17,10 +17,14 @@ action("brave-extension") {
"$target_gen_dir/brave_extension/build/js/braveShieldsPanel.bundle.js",
"$target_gen_dir/brave_extension/build/braveShieldsPanel.html",
"$target_gen_dir/brave_extension/build/bravelizer.css",
- "$target_gen_dir/brave_extension/build/img/icon-128.png",
"$target_gen_dir/brave_extension/build/img/icon-16.png",
- "$target_gen_dir/brave_extension/build/img/icon-16-disabled.png",
+ "$target_gen_dir/brave_extension/build/img/icon-32.png",
"$target_gen_dir/brave_extension/build/img/icon-48.png",
+ "$target_gen_dir/brave_extension/build/img/icon-64.png",
+ "$target_gen_dir/brave_extension/build/img/icon-128.png",
+ "$target_gen_dir/brave_extension/build/img/icon-256.png",
+ "$target_gen_dir/brave_extension/build/img/icon.svg",
+ "$target_gen_dir/brave_extension/build/img/icon-off.svg",
"$target_gen_dir/brave_extension/build/_locales/en_US/messages.json",
]
diff --git a/app/actions/runtimeActions.ts b/app/actions/runtimeActions.ts
new file mode 100644
index 0000000..8c32575
--- /dev/null
+++ b/app/actions/runtimeActions.ts
@@ -0,0 +1,11 @@
+/* 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/. */
+
+import * as types from '../constants/runtimeActionTypes'
+
+export function runtimeDidStartup () {
+ return {
+ type: types.RUNTIME_DID_STARTUP
+ }
+}
diff --git a/app/assets/img/icon-128.png b/app/assets/img/icon-128.png
index 10fe418..67cc0aa 100644
Binary files a/app/assets/img/icon-128.png and b/app/assets/img/icon-128.png differ
diff --git a/app/assets/img/icon-16-disabled.png b/app/assets/img/icon-16-disabled.png
deleted file mode 100644
index 414158d..0000000
Binary files a/app/assets/img/icon-16-disabled.png and /dev/null differ
diff --git a/app/assets/img/icon-16.png b/app/assets/img/icon-16.png
index 9957ca0..a1d6f2b 100644
Binary files a/app/assets/img/icon-16.png and b/app/assets/img/icon-16.png differ
diff --git a/app/assets/img/icon-256.png b/app/assets/img/icon-256.png
new file mode 100644
index 0000000..7c1e117
Binary files /dev/null and b/app/assets/img/icon-256.png differ
diff --git a/app/assets/img/icon-32.png b/app/assets/img/icon-32.png
new file mode 100644
index 0000000..dc68225
Binary files /dev/null and b/app/assets/img/icon-32.png differ
diff --git a/app/assets/img/icon-48.png b/app/assets/img/icon-48.png
index 643e14b..f9d29f7 100644
Binary files a/app/assets/img/icon-48.png and b/app/assets/img/icon-48.png differ
diff --git a/app/assets/img/icon-64.png b/app/assets/img/icon-64.png
new file mode 100644
index 0000000..ce14c23
Binary files /dev/null and b/app/assets/img/icon-64.png differ
diff --git a/app/assets/img/icon-off.svg b/app/assets/img/icon-off.svg
new file mode 100644
index 0000000..d31649d
--- /dev/null
+++ b/app/assets/img/icon-off.svg
@@ -0,0 +1,7 @@
+
\ No newline at end of file
diff --git a/app/assets/img/icon.svg b/app/assets/img/icon.svg
new file mode 100644
index 0000000..503f594
--- /dev/null
+++ b/app/assets/img/icon.svg
@@ -0,0 +1,7 @@
+
\ No newline at end of file
diff --git a/app/background/actions/runtimeActions.ts b/app/background/actions/runtimeActions.ts
new file mode 100644
index 0000000..f3852f2
--- /dev/null
+++ b/app/background/actions/runtimeActions.ts
@@ -0,0 +1,8 @@
+/* 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/. */
+
+import { bindActionCreators } from 'redux'
+import store from '../store'
+import * as runtimeActions from '../../actions/runtimeActions'
+export default bindActionCreators(runtimeActions, store.dispatch)
diff --git a/app/background/api/browserActionAPI.ts b/app/background/api/browserActionAPI.ts
index 4d05937..97032d6 100644
--- a/app/background/api/browserActionAPI.ts
+++ b/app/background/api/browserActionAPI.ts
@@ -4,13 +4,37 @@
import { isHttpOrHttps } from '../../helpers/urlUtils'
+export const shieldsOnIcon = 'img/icon.svg'
+export const shieldsOffIcon = 'img/icon-off.svg'
+
+/**
+ * Initializes the browser action UI
+ */
+export function init () {
+ // Setup badge color
+ chrome.browserAction.setBadgeBackgroundColor({
+ color: [66, 66, 66, 100]
+ })
+ // Initial / default icon
+ chrome.browserAction.setIcon({
+ path: shieldsOnIcon
+ })
+ // By default, icon is disabled,
+ // so that we do not enable the icon in a new tab and then disable it
+ // when the context is not http(s).
+ chrome.browserAction.disable()
+}
+
/**
* Sets the badge text
* @param {string} text - The text to put on the badge
*/
-export const setBadgeText = (text: string) => {
+export const setBadgeText = (tabId: number, text: string) => {
if (chrome.browserAction) {
- chrome.browserAction.setBadgeText({ text: String(text) })
+ chrome.browserAction.setBadgeText({
+ tabId,
+ text: String(text)
+ })
}
}
@@ -18,13 +42,17 @@ export const setBadgeText = (text: string) => {
* Updates the shields icon based on shields state
*/
export const setIcon = (url: string, tabId: number, shieldsOn: boolean) => {
- const shieldsEnabledIcon = 'img/icon-16.png'
- const shieldsDisabledIcon = 'img/icon-16-disabled.png'
+ const actionIsDisabled = !isHttpOrHttps(url)
if (chrome.browserAction) {
chrome.browserAction.setIcon({
- path: shieldsOn && isHttpOrHttps(url) ? shieldsEnabledIcon : shieldsDisabledIcon,
+ path: shieldsOn ? shieldsOnIcon : shieldsOffIcon,
tabId
})
+ if (actionIsDisabled) {
+ chrome.browserAction.disable(tabId)
+ } else {
+ chrome.browserAction.enable(tabId)
+ }
}
}
diff --git a/app/background/events/runtimeEvents.ts b/app/background/events/runtimeEvents.ts
index ff124da..459164c 100644
--- a/app/background/events/runtimeEvents.ts
+++ b/app/background/events/runtimeEvents.ts
@@ -4,8 +4,10 @@
import windowActions from '../actions/windowActions'
import tabActions from '../actions/tabActions'
+import runtimeActions from '../actions/runtimeActions'
chrome.runtime.onStartup.addListener(() => {
+ runtimeActions.runtimeDidStartup()
chrome.windows.getAllAsync({ populate: true }).then((windows: chrome.windows.Window[]) => {
windows.forEach((win: chrome.windows.Window) => {
windowActions.windowCreated(win)
diff --git a/app/background/reducers.ts b/app/background/reducers.ts
index 26afa33..2e80973 100644
--- a/app/background/reducers.ts
+++ b/app/background/reducers.ts
@@ -6,8 +6,10 @@ import { combineReducers } from 'redux'
import shieldsPanelReducer from './reducers/shieldsPanelReducer'
import cosmeticFilterReducer from './reducers/cosmeticFilterReducer'
+import runtimeReducer from './reducers/runtimeReducer'
export default combineReducers({
shieldsPanel: shieldsPanelReducer,
- cosmeticFilter: cosmeticFilterReducer
+ cosmeticFilter: cosmeticFilterReducer,
+ runtime: runtimeReducer
})
diff --git a/app/background/reducers/runtimeReducer.ts b/app/background/reducers/runtimeReducer.ts
new file mode 100644
index 0000000..f343436
--- /dev/null
+++ b/app/background/reducers/runtimeReducer.ts
@@ -0,0 +1,15 @@
+import { Actions } from '../../types/actions'
+import * as runtimeActions from '../../constants/runtimeActionTypes'
+import * as browserActionAPI from '../api/browserActionAPI'
+
+type State = { }
+
+export default function runtimeReducer (state: State = { }, action: Actions): State {
+ switch (action.type) {
+ case runtimeActions.RUNTIME_DID_STARTUP: {
+ browserActionAPI.init()
+ break
+ }
+ }
+ return state
+}
diff --git a/app/background/reducers/shieldsPanelReducer.ts b/app/background/reducers/shieldsPanelReducer.ts
index b395a2d..11b5d49 100644
--- a/app/background/reducers/shieldsPanelReducer.ts
+++ b/app/background/reducers/shieldsPanelReducer.ts
@@ -30,7 +30,7 @@ const updateBadgeText = (state: State) => {
if (tab) {
const total = tab.adsBlocked + tab.trackersBlocked + tab.javascriptBlocked + tab.fingerprintingBlocked + tab.httpsRedirected
// do not show any badge if there are no blocked items
- setBadgeText(total > 0 ? total.toString() : '')
+ setBadgeText(tabId, total > 99 ? '99+' : total > 0 ? total.toString() : '')
}
}
diff --git a/app/constants/runtimeActionTypes.ts b/app/constants/runtimeActionTypes.ts
new file mode 100644
index 0000000..94d7311
--- /dev/null
+++ b/app/constants/runtimeActionTypes.ts
@@ -0,0 +1 @@
+export const RUNTIME_DID_STARTUP = 'RUNTIME_DID_STARTUP'
diff --git a/app/manifest.dev.json b/app/manifest.dev.json
index e336bc8..898c89c 100644
--- a/app/manifest.dev.json
+++ b/app/manifest.dev.json
@@ -10,8 +10,11 @@
},
"icons": {
"16": "img/icon-16.png",
+ "32": "img/icon-32.png",
"48": "img/icon-48.png",
- "128": "img/icon-128.png"
+ "64": "img/icon-64.png",
+ "128": "img/icon-128.png",
+ "256": "img/icon-256.png"
},
"web_accessible_resources": [
],
diff --git a/app/manifest.prod.json b/app/manifest.prod.json
index 7bf7a38..01fc547 100644
--- a/app/manifest.prod.json
+++ b/app/manifest.prod.json
@@ -10,8 +10,11 @@
},
"icons": {
"16": "img/icon-16.png",
+ "32": "img/icon-32.png",
"48": "img/icon-48.png",
- "128": "img/icon-128.png"
+ "64": "img/icon-64.png",
+ "128": "img/icon-128.png",
+ "256": "img/icon-256.png"
},
"web_accessible_resources": [
],
diff --git a/app/types/actions/index.ts b/app/types/actions/index.ts
index 62d952e..c7ac38f 100644
--- a/app/types/actions/index.ts
+++ b/app/types/actions/index.ts
@@ -3,10 +3,12 @@ import { tabActions } from './tabActions'
import { webNavigationActions } from './webNavigationActions'
import { windowActions } from './windowActions'
import { cosmeticFilterActions } from './cosmeticFilterActions'
+import { runtimeActions } from './runtimeActions'
export type Actions =
shieldPanelActions |
tabActions |
webNavigationActions |
windowActions |
- cosmeticFilterActions
+ cosmeticFilterActions |
+ runtimeActions
diff --git a/app/types/actions/runtimeActions.ts b/app/types/actions/runtimeActions.ts
new file mode 100644
index 0000000..a0856ee
--- /dev/null
+++ b/app/types/actions/runtimeActions.ts
@@ -0,0 +1,11 @@
+import * as types from '../../constants/runtimeActionTypes'
+
+interface RuntimeDidStartupReturn {
+ type: typeof types.RUNTIME_DID_STARTUP
+}
+
+export interface RuntimeDidStartup {
+ (): RuntimeDidStartupReturn
+}
+
+export type runtimeActions = RuntimeDidStartupReturn
diff --git a/test/app/background/api/browserActionAPITest.ts b/test/app/background/api/browserActionAPITest.ts
index 3547b8a..aaf6757 100644
--- a/test/app/background/api/browserActionAPITest.ts
+++ b/test/app/background/api/browserActionAPITest.ts
@@ -13,7 +13,8 @@ describe('BrowserAction API', () => {
before(function () {
this.spy = sinon.spy(chrome.browserAction, 'setBadgeText')
this.text = '42'
- browserActionAPI.setBadgeText(this.text)
+ this.tabId = 1337
+ browserActionAPI.setBadgeText(this.tabId, this.text)
})
after(function () {
this.spy.restore()
@@ -21,55 +22,52 @@ describe('BrowserAction API', () => {
it('calls chrome.browserAction.setBadgeText with the text', function () {
assert(this.spy.calledOnce)
assert.deepEqual(this.spy.getCall(0).args[0], {
+ tabId: this.tabId,
text: this.text
})
})
})
describe('setIcon', function () {
- const enabledIconPath = 'img/icon-16.png'
- const disabledIconPath = 'img/icon-16-disabled.png'
before(function () {
- this.spy = sinon.spy(chrome.browserAction, 'setIcon')
+ this.setIconSpy = sinon.spy(chrome.browserAction, 'setIcon')
+ this.disableSpy = sinon.spy(chrome.browserAction, 'disable')
+ this.enableSpy = sinon.spy(chrome.browserAction, 'enable')
this.url = 'https://brave.com'
this.tabId = 1
this.shieldsEnabled = true
})
after(function () {
- this.spy.restore()
+ this.setIconSpy.restore()
+ this.disableSpy.restore()
+ this.enableSpy.restore()
})
afterEach(function () {
- this.spy.reset()
+ this.setIconSpy.reset()
+ this.disableSpy.reset()
+ this.enableSpy.reset()
})
- it('sets the enabled icon when protocol is http', function () {
+ it('sets enabled when protocol is http', function () {
this.url = 'http://not-very-awesome-http-page.com'
browserActionAPI.setIcon(this.url, this.tabId, this.shieldsEnabled)
- assert.deepEqual(this.spy.getCall(0).args[0], {
- path: enabledIconPath,
- tabId: this.tabId
- })
+ assert.deepEqual(this.enableSpy.getCall(0).args[0], this.tabId)
})
it('sets the enabled icon when protocol is https', function () {
this.url = 'https://very-awesome-https-page.com'
browserActionAPI.setIcon(this.url, this.tabId, this.shieldsEnabled)
- assert.deepEqual(this.spy.getCall(0).args[0], {
- path: enabledIconPath,
- tabId: this.tabId
- })
+ assert.deepEqual(this.enableSpy.getCall(0).args[0], this.tabId)
})
it('sets the disabled icon when the protocol is neither https nor http', function () {
this.url = 'brave://welcome'
browserActionAPI.setIcon(this.url, this.tabId, this.shieldsEnabled)
- assert.deepEqual(this.spy.getCall(0).args[0], {
- path: disabledIconPath,
- tabId: this.tabId
- })
+ assert.deepEqual(this.disableSpy.getCall(0).args[0], this.tabId)
})
it('sets the disabled icon when the protocol is http and shield is off', function () {
this.url = 'http://not-very-awesome-http-page.com'
this.shieldsEnabled = false
browserActionAPI.setIcon(this.url, this.tabId, this.shieldsEnabled)
- assert.deepEqual(this.spy.getCall(0).args[0], {
- path: disabledIconPath,
+ assert.deepEqual(this.enableSpy.getCall(0).args[0], this.tabId)
+ assert.deepEqual(this.setIconSpy.getCall(0).args[0], {
+ path: browserActionAPI.shieldsOffIcon,
tabId: this.tabId
})
})
@@ -77,8 +75,9 @@ describe('BrowserAction API', () => {
this.url = 'https://very-awesome-https-page.com'
this.shieldsEnabled = false
browserActionAPI.setIcon(this.url, this.tabId, this.shieldsEnabled)
- assert.deepEqual(this.spy.getCall(0).args[0], {
- path: disabledIconPath,
+ assert.deepEqual(this.enableSpy.getCall(0).args[0], this.tabId)
+ assert.deepEqual(this.setIconSpy.getCall(0).args[0], {
+ path: browserActionAPI.shieldsOffIcon,
tabId: this.tabId
})
})
diff --git a/test/app/background/reducers/shieldsPanelReducerTest.ts b/test/app/background/reducers/shieldsPanelReducerTest.ts
index e0653f8..7db9ad0 100644
--- a/test/app/background/reducers/shieldsPanelReducerTest.ts
+++ b/test/app/background/reducers/shieldsPanelReducerTest.ts
@@ -490,7 +490,7 @@ describe('braveShieldsPanelReducer', () => {
}
})
assert.equal(this.spy.calledOnce, true)
- assert.equal(this.spy.getCall(0).args[0], '12')
+ assert.equal(this.spy.getCall(0).args[1], '12')
})
it('increments for JS blocking', function () {
let nextState = shieldsPanelReducer(state, {
diff --git a/test/testData.ts b/test/testData.ts
index 1857f3d..ac0ad40 100644
--- a/test/testData.ts
+++ b/test/testData.ts
@@ -74,8 +74,11 @@ export const getMockChrome = () => {
onStartup: new ChromeEvent()
},
browserAction: {
- setBadgeText: function (text: string) {},
- setIcon: function (icon: string, tabId: number) {}
+ setBadgeBackgroundColor: function (properties: object) {},
+ setBadgeText: function (textProperties: object) {},
+ setIcon: function (iconProperties: object) {},
+ enable: function (tabId?: number) {},
+ disable: function (tabId?: number) {}
},
tabs: {
queryAsync: function () {
@@ -149,6 +152,7 @@ export const initialState = deepFreeze({
tabs: {},
windows: {}
},
+ runtime: {},
shieldsPanel: {
currentWindowId: -1,
tabs: {},