Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Butter bar alerts! 🧈 #146

Merged
merged 9 commits into from
Dec 13, 2024
Merged
Show file tree
Hide file tree
Changes from 8 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
3 changes: 3 additions & 0 deletions src/assets/img/close.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
129 changes: 129 additions & 0 deletions src/background/butterBarService.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/* 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/. */

// @ts-check
import { Component } from "./component.js";
import { PropertyType } from "../shared/ipc.js";

import { IBindable, property } from "../shared/property.js";
import { VPNController } from "./vpncontroller/vpncontroller.js";
import { ConflictObserver } from "./conflictObserver.js";

/**
*
* ButterBarService manages 'Butter Bar' alerts shown
* in the UI.
*/

export class ButterBarService extends Component {
// Gets exposed to UI
static properties = {
butterBarList: PropertyType.Bindable,
removeAlert: PropertyType.Function,
};

/** @type {IBindable<Array<ButterBarAlert>>} */
// List of alerts passed to the UI
butterBarList = property([]);

/** @type {Array<String>} */
// List of alert IDs that have been dismissed
dismissedAlerts = [];

/**
*
* @param {*} receiver
* @param {VPNController} vpnController
* @param {ConflictObserver} conflictObserver
*/
constructor(receiver, vpnController, conflictObserver) {
super(receiver);
this.vpnController = vpnController;
this.conflictObserver = conflictObserver;
}

async init() {
console.log("Initializing ButterBarService");
await this.conflictObserver.updateList();

this.vpnController.interventions.subscribe((interventions) => {
const alert = new ButterBarAlert(
"conflictingProgram",
"alert_conflictingProgram",
"howToFix",
"https://support.mozilla.org/kb/program-your-computer-interferes-mozilla-vpn-exten?utm_medium=mozilla-vpn&utm_source=vpn-extension"
);
this.maybeCreateAlert(interventions, alert);
});

this.conflictObserver.conflictingAddons.subscribe((conflictingAddons) => {
const alert = new ButterBarAlert(
"alert_conflictingExtensions",
"alert_conflictingExtensions",
"learnWhatToDo",
"https://support.mozilla.org/kb/if-another-extension-interferes-mozilla-vpn?utm_medium=mozilla-vpn&utm_source=vpn-extension"
);

this.maybeCreateAlert(conflictingAddons, alert);
});
}
/**
* @param {Array} list
* @param {ButterBarAlert} alert
*/
maybeCreateAlert(list, alert) {
if (list.length == 0) {
return;
}
const { alertId } = alert;

if (
this.alertWasDismissed(alertId, this.dismissedAlerts) ||
this.alertInButterBarList(alertId, this.butterBarList.value)
) {
return;
}

return this.butterBarList.value.push(alert);
}

/**
* @param {string} id
* @param {Array} dismissedAlerts
*/
alertWasDismissed(id, dismissedAlerts) {
return dismissedAlerts.some((alertId) => alertId == id);
}

/**
* @param {string} id
* @param {Array} butterBarList
*/
alertInButterBarList(id, butterBarList) {
return butterBarList.some((alert) => alert.alertId == id);
}

removeAlert(id) {
const newAlertList = this.butterBarList.value.filter(
({ alertId }) => alertId !== id
);
this.dismissedAlerts.push(id);
return this.butterBarList.set(newAlertList);
Copy link
Collaborator

Choose a reason for hiding this comment

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

property.set returns void. Should this return a value?

}
}

export class ButterBarAlert {
/**
* @param {string} alertId
* @param {string} alertMessage
* @param {string} linkText
* @param {string} linkUrl
*/
constructor(alertId, alertMessage, linkText, linkUrl) {
(this.alertId = alertId),
lesleyjanenorton marked this conversation as resolved.
Show resolved Hide resolved
(this.alertMessage = alertMessage),
(this.linkText = linkText),
(this.linkUrl = linkUrl);
}
}
6 changes: 5 additions & 1 deletion src/background/conflictObserver.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ export class ConflictObserver {
* @returns {boolean}
*/
static isConflicting(addon) {
return addon.enabled && addon.permissions.includes("proxy");
return (
addon.enabled &&
addon.permissions.includes("proxy") &&
addon.id !== "[email protected]"
Copy link
Collaborator

Choose a reason for hiding this comment

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

q__q oh wow how could i miss that.

);
}
}
8 changes: 8 additions & 0 deletions src/background/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import { ExtensionController } from "./extensionController/index.js";
import { expose } from "../shared/ipc.js";
import { TabReloader } from "./tabReloader.js";
import { ConflictObserver } from "./conflictObserver.js";
import { ButterBarService } from "./butterBarService.js";

const log = Logger.logger("Main");

class Main {
Expand Down Expand Up @@ -43,6 +45,11 @@ class Main {
this.vpnController
);
tabReloader = new TabReloader(this, this.extController, this.proxyHandler);
butterBarService = new ButterBarService(
this,
this.vpnController,
this.conflictObserver
);

async init() {
log("Hello from the background script!");
Expand All @@ -54,6 +61,7 @@ class Main {
expose(this.extController);
expose(this.proxyHandler);
expose(this.conflictObserver);
expose(this.butterBarService);

this.#handlingEvent = false;
this.#processPendingEvents();
Expand Down
3 changes: 3 additions & 0 deletions src/background/tabHandler.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ export class TabHandler extends Component {
}

async maybeShowIcon() {
if (!this.siteContexts) {
return;
}
const currentTab = await Utils.getCurrentTab();
if (!currentTab) {
return;
Expand Down
120 changes: 120 additions & 0 deletions src/components/butter-bar.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/* 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 { html, LitElement, css } from "../vendor/lit-all.min.js";
import { ghostButtonStyles } from "../components/styles.js";
import { tr } from "../shared/i18n.js";
import { butterBarService } from "../../ui/browserAction/backend.js";

export class ButterBar extends LitElement {
static properties = {
alertId: { type: String },
alertMessage: { type: String },
linkText: { type: String },
linkUrl: { type: String },
};

constructor() {
super();
this.alertId = "";
this.alertMessage = "";
this.linkText = "";
this.linkUrl = "";
}

render() {
const openLink = (url) => {
browser.tabs.create({ url });
window.close();
};

const removeAlert = (id) => {
butterBarService.removeAlert(id);
this.dispatchEvent(new CustomEvent("resize-popup", { bubbles: true }));
};

return html`
<div class="butter-bar">
<div class="butter-bar-text">
<p>
${tr(this.alertMessage)}<a
href=""
@click=${() => {
openLink(this.linkUrl);
}}
>${tr(this.linkText)}</a
>
</p>
</div>
<button
@click=${() => {
removeAlert(this.alertId);
}}
class="butter-bar-close ghost-btn"
>
<img aria-hidden="true" src="./../../assets/img/close.svg" />
</button>
</div>
`;
}

static styles = css`
${ghostButtonStyles}
.butter-bar {
margin-block-end: 16px;
background: var(--grey10);
border-radius: 4px;
display: flex;
flex-direction: row;
justify-content: space-between;
overflow: clip;
}

.butter-bar-text {
text-align: center;
flex: 1;
font-size: 13px;
padding: 8px 16px;
}

button.butter-bar-close.ghost-btn {
inline-size: 40px;
border: none;
}

button.butter-bar-close.ghost-btn::before {
border-radius: 0px;
}

a {
margin-inline-start: 5px;
font-family: "Inter Semi Bold";
color: inherit;
}

a:hover {
color: #000000;
opacity: 1;
transition: opacity 0.2s ease-in-out;
}

@media (prefers-color-scheme: dark) {
.butter-bar {
background: rgba(255, 255, 255, 0.02);
}

a:hover {
opacity: 0.7;
color: #ffffff;
}
a:active {
opacity: 0.5;
}
img {
filter: invert();
}
}
`;
}
customElements.define("butter-bar", ButterBar);
1 change: 1 addition & 0 deletions src/ui/browserAction/backend.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,6 @@ import { getExposedObject } from "../../shared/ipc.js";
export const vpnController = await getExposedObject("VPNController");
export const extController = await getExposedObject("ExtensionController");
export const proxyHandler = await getExposedObject("ProxyHandler");
export const butterBarService = await getExposedObject("ButterBarService");

export const ready = Promise.all([vpnController, proxyHandler]);
27 changes: 25 additions & 2 deletions src/ui/browserAction/popupPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@ import {
live,
} from "../../vendor/lit-all.min.js";

import { vpnController, proxyHandler, extController } from "./backend.js";
import {
vpnController,
proxyHandler,
extController,
butterBarService,
} from "./backend.js";

import { Utils } from "../../shared/utils.js";
import { tr } from "../../shared/i18n.js";
Expand All @@ -31,6 +36,7 @@ import "./../../components/vpncard.js";
import "./../../components/titlebar.js";
import "./../../components/iconbutton.js";
import "./../../components/mz-rings.js";
import "./../../components/butter-bar.js";
import { SiteContext } from "../../background/proxyHandler/siteContext.js";
import {
ServerCity,
Expand Down Expand Up @@ -58,6 +64,7 @@ export class BrowserActionPopup extends LitElement {
_siteContext: { type: Object },
hasSiteContext: { type: Boolean },
_siteContexts: { type: Array },
alerts: { type: Array },
};

constructor() {
Expand All @@ -74,10 +81,13 @@ export class BrowserActionPopup extends LitElement {
this._siteContexts = s;
});
extController.state.subscribe((s) => {
console.log(s);
this.extState = s;
this.updatePage();
});
butterBarService.butterBarList.subscribe((s) => {
this.alerts = s;
this.updatePage();
});
this.updatePage();
}
updatePage() {
Expand Down Expand Up @@ -172,6 +182,19 @@ export class BrowserActionPopup extends LitElement {
<stack-view ${ref(this.stackView)}>
<section data-title="Mozilla VPN">
<main>
<div class="butter-bar-holder">
${this.alerts.map(
(alert) => html`
<butter-bar
.alertId=${alert.alertId}
.alertMessage=${alert.alertMessage}
.linkText=${alert.linkText}
.linkUrl=${alert.linkUrl}
>
</butter-bar>
`
)}
</div>
<vpn-card
@toggle=${handleVPNToggle}
.enabled=${this.extState?.enabled}
Expand Down
1 change: 1 addition & 0 deletions src/ui/variables.css
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
--green50: #3fe1b0;
--green60: #3ad4b3;
--green70: #1cc4a0;
--grey10: #e7e7e7;
--grey30: #9e9e9e;
--grey40: #6d6d6e;
--grey50: #3d3d3d;
Expand Down
Loading
Loading