Finish notification system (for now)
This commit is contained in:
parent
12b15c58f8
commit
0310e1e2de
14
src/common/data/notifications.js
Normal file
14
src/common/data/notifications.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
let Notifications = Object.freeze({
|
||||||
|
'TEST_NOTIFICATION': {
|
||||||
|
icon: 'card-text',
|
||||||
|
text: 'This is a test notification.',
|
||||||
|
timeout: -1,
|
||||||
|
},
|
||||||
|
'AARD_DRM': {
|
||||||
|
icon: 'exclamation-triangle',
|
||||||
|
text: '<b>Autodetection cannot run on this video.</b> This usually happens when sites use DRM. You will have to set aspect ratio manually.',
|
||||||
|
timeout: 5000,
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export default Notifications;
|
@ -5,11 +5,10 @@
|
|||||||
<Icon
|
<Icon
|
||||||
class="flex-nogrow flex-noshrink"
|
class="flex-nogrow flex-noshrink"
|
||||||
:icon="notificationIcon"
|
:icon="notificationIcon"
|
||||||
@click="closeNotification()"
|
|
||||||
>
|
>
|
||||||
</Icon>
|
</Icon>
|
||||||
</div>
|
</div>
|
||||||
<div class="notification-context flex-grow flex-shrink flex flex-column">
|
<div class="notification-content flex-grow flex-shrink flex flex-column flex-cross-center">
|
||||||
<div
|
<div
|
||||||
class="notification-text"
|
class="notification-text"
|
||||||
v-html="notificationText"
|
v-html="notificationText"
|
||||||
@ -21,18 +20,41 @@
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-for="action of notificationActions"
|
v-for="action of notificationActions"
|
||||||
|
class="action-button"
|
||||||
:key="action"
|
:key="action"
|
||||||
@click="action.command"
|
@click="action.command"
|
||||||
>
|
>
|
||||||
<Icon v-if="action.icon" :icon="action.icon"></Icon>{{action.label}}
|
<Icon v-if="action.icon" :icon="action.icon"></Icon>{{action.label}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="hideActions"
|
||||||
|
class="hide-actions"
|
||||||
|
>
|
||||||
|
Never show again:<wbr>
|
||||||
|
<template
|
||||||
|
v-for="action of hideActions"
|
||||||
|
:key="action"
|
||||||
|
>
|
||||||
|
<i @click="closeNotification">
|
||||||
|
<a
|
||||||
|
class="hide-action-button"
|
||||||
|
@click="action.command"
|
||||||
|
>
|
||||||
|
{{action.label}}
|
||||||
|
</a>
|
||||||
|
<wbr>
|
||||||
|
</i>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="notification-icon">
|
<div
|
||||||
|
class="notification-icon action-button"
|
||||||
|
@click="closeNotification()"
|
||||||
|
>
|
||||||
<Icon
|
<Icon
|
||||||
class="flex-nogrow flex-noshrink"
|
class="flex-nogrow flex-noshrink"
|
||||||
icon="x"
|
icon="x"
|
||||||
@click="closeNotification()"
|
|
||||||
>
|
>
|
||||||
</Icon>
|
</Icon>
|
||||||
</div>
|
</div>
|
||||||
@ -50,20 +72,19 @@ export default {
|
|||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
// notificationIcon: null,
|
|
||||||
// notificationText: null,
|
|
||||||
// notificationActions: null,
|
|
||||||
// showNotification: false,
|
|
||||||
notificationTimeout: null,
|
notificationTimeout: null,
|
||||||
notificationIcon: "exclamation-triangle",
|
notificationIcon: "exclamation-triangle",
|
||||||
notificationText: "this is a test notification <b>with some html for bold measure</b>",
|
notificationText: "<b>Sample text.</b> This will be replaced with real notification later.",
|
||||||
notificationActions: null,
|
notificationActions: null,
|
||||||
showNotification: true,
|
hideActions: null,
|
||||||
|
showNotification: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
...mapState([
|
computed: {
|
||||||
'notificationConfig'
|
...mapState([
|
||||||
]),
|
'notificationConfig'
|
||||||
|
]),
|
||||||
|
},
|
||||||
watch: {
|
watch: {
|
||||||
/**
|
/**
|
||||||
* Sets new notification config. Currently, we can only show one notification at a time.
|
* Sets new notification config. Currently, we can only show one notification at a time.
|
||||||
@ -79,31 +100,39 @@ export default {
|
|||||||
* label: label of the button
|
* label: label of the button
|
||||||
* icon: icon of the button
|
* icon: icon of the button
|
||||||
* }
|
* }
|
||||||
|
* ],
|
||||||
|
* hideOptions: [
|
||||||
|
* // more of notificationActions except it's a special case
|
||||||
* ]
|
* ]
|
||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
notificationConfig(newConfig) {
|
notificationConfig(newConfig) {
|
||||||
|
console.log('notificationConfig?');
|
||||||
if (newConfig) {
|
if (newConfig) {
|
||||||
this.notificationText = newConfig.text;
|
this.notificationText = newConfig.text;
|
||||||
this.notificationActions = newConfig.notificationActions;
|
this.notificationActions = newConfig.notificationActions;
|
||||||
this.notificationIcon = newConfig.icon;
|
this.notificationIcon = newConfig.icon;
|
||||||
|
this.hideActions = newConfig.hideActions;
|
||||||
|
|
||||||
this.showNotification = true;
|
this.showNotification = true;
|
||||||
|
|
||||||
if (newConfig.timeout !== -1) {
|
if (newConfig.timeout !== -1) {
|
||||||
this.notificationTimeout = setTimeout(() => this.closeNotification(), newConfig.timeout ?? 10000);
|
this.notificationTimeout = setTimeout(() => this.closeNotification(), newConfig.timeout ?? 5000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
closeNotification() {
|
closeNotification() {
|
||||||
|
console.log("close notification!")
|
||||||
|
|
||||||
clearTimeout(this.notificationTimeout);
|
clearTimeout(this.notificationTimeout);
|
||||||
|
|
||||||
this.showNotification = false;
|
this.showNotification = false;
|
||||||
this.notificationIcon = null;
|
this.notificationIcon = null;
|
||||||
this.notificationText = null;
|
this.notificationText = null;
|
||||||
this.notificationActions = null;
|
this.notificationActions = null;
|
||||||
|
this.hideActions = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -120,18 +149,62 @@ export default {
|
|||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
pointer-events: none;
|
||||||
|
|
||||||
|
font-size: 16px;
|
||||||
|
|
||||||
.notification-popup {
|
.notification-popup {
|
||||||
|
pointer-events: auto !important;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 99999999;
|
z-index: 99999999;
|
||||||
|
top: 2em;
|
||||||
|
right: 2em;
|
||||||
|
width: 32em;
|
||||||
|
|
||||||
|
padding: 0.7em 0.5em;
|
||||||
|
|
||||||
|
font-family: 'Overpass';
|
||||||
|
|
||||||
background-color: rgba(108, 55, 12, 0.779);
|
background-color: rgba(108, 55, 12, 0.779);
|
||||||
top: 2rem;
|
|
||||||
left: 2rem;
|
|
||||||
width: 15rem;
|
|
||||||
color: #fff;
|
color: #fff;
|
||||||
|
|
||||||
|
user-select: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.notifcation-content {
|
||||||
|
margin-left: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.notification-text {
|
||||||
|
text-align: justify;
|
||||||
|
}
|
||||||
|
|
||||||
.notification-icon {
|
.notification-icon {
|
||||||
font-size: 3rem;
|
font-size: 3em;
|
||||||
|
line-height: 0.5;
|
||||||
|
}
|
||||||
|
.action-button {
|
||||||
|
pointer-events: auto;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hide-actions {
|
||||||
|
color: #ccc;
|
||||||
|
font-size: 0.8em;
|
||||||
|
justify-self: flex-end;
|
||||||
|
align-self: flex-end;
|
||||||
|
margin-top: 1em;
|
||||||
|
margin-bottom: -1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hide-action-button {
|
||||||
|
color: #eee;
|
||||||
|
font-size: 0.9em;
|
||||||
|
text-decoration: underline;
|
||||||
|
text-decoration-color: rgba(255,255,255,0.5);
|
||||||
|
|
||||||
|
pointer-events: auto;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
@ -1,23 +1,31 @@
|
|||||||
import UI from './UI';
|
import UI from './UI';
|
||||||
import VuexWebExtensions from 'vuex-webextensions';
|
import VuexWebExtensions from 'vuex-webextensions';
|
||||||
import NotificationUi from '../../../csui/NotificationUi.vue';
|
import NotificationUi from '../../../csui/NotificationUi.vue';
|
||||||
|
import Notifications from '../../../common/data/notifications';
|
||||||
|
|
||||||
if (process.env.CHANNEL !== 'stable'){
|
if (process.env.CHANNEL !== 'stable'){
|
||||||
console.info("Loading: PlayerNotificationUi");
|
console.info("Loading: PlayerNotificationUi");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let MuteScope = Object.freeze({
|
||||||
|
CurrentSite: 'current-site',
|
||||||
|
Global: 'global'
|
||||||
|
});
|
||||||
|
|
||||||
class PlayerNotificationUi extends UI {
|
class PlayerNotificationUi extends UI {
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
playerElement
|
playerElement,
|
||||||
) {
|
settings
|
||||||
|
) {
|
||||||
super(
|
super(
|
||||||
'notification',
|
'notification',
|
||||||
PlayerNotificationUi.getStoreConfig(),
|
PlayerNotificationUi.getStoreConfig(),
|
||||||
PlayerNotificationUi.getUiConfig(playerElement),
|
PlayerNotificationUi.getUiConfig(playerElement),
|
||||||
PlayerNotificationUi.getCommsConfig()
|
PlayerNotificationUi.getCommsConfig()
|
||||||
)
|
);
|
||||||
|
|
||||||
|
this.settings = settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -42,11 +50,13 @@ class PlayerNotificationUi extends UI {
|
|||||||
},
|
},
|
||||||
mutations: {
|
mutations: {
|
||||||
'uw-set-notification'(state, payload) {
|
'uw-set-notification'(state, payload) {
|
||||||
|
console.log('mutation!', state, payload);
|
||||||
state['notificationConfig'] = payload;
|
state['notificationConfig'] = payload;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
actions: {
|
actions: {
|
||||||
'uw-set-notification'({commit}, payload) {
|
'uw-set-notification'({commit}, payload) {
|
||||||
|
console.log('action!', commit, payload);
|
||||||
commit('uw-set-notification', payload);
|
commit('uw-set-notification', payload);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -78,7 +88,7 @@ class PlayerNotificationUi extends UI {
|
|||||||
/**
|
/**
|
||||||
* Show notification on screen.
|
* Show notification on screen.
|
||||||
*
|
*
|
||||||
* @param notificationConfig notification config
|
* @param notificationConfig notification config (or ID of notification config in /common/data/notifications.js)
|
||||||
*
|
*
|
||||||
* notificationConfig should resemble this:
|
* notificationConfig should resemble this:
|
||||||
* {
|
* {
|
||||||
@ -91,11 +101,79 @@ class PlayerNotificationUi extends UI {
|
|||||||
* label: label of the button
|
* label: label of the button
|
||||||
* icon: icon of the button
|
* icon: icon of the button
|
||||||
* }
|
* }
|
||||||
|
* ],
|
||||||
|
* hideActions: [
|
||||||
|
* // more of notificationActions but with special case
|
||||||
* ]
|
* ]
|
||||||
* }
|
* }
|
||||||
|
*
|
||||||
|
* When notificationConfig is a string, the function will add two additional notifications on the notificationActionsPile
|
||||||
|
* * never show this notification ever again on any site
|
||||||
|
* * never show this notification again on this site
|
||||||
*/
|
*/
|
||||||
showNotification(notificationConfig) {
|
showNotification(notificationConfig) {
|
||||||
this.vuexStore?.dispatch('uw-set-notification', notificationConfig);
|
if (typeof notificationConfig === 'string') {
|
||||||
|
try {
|
||||||
|
const config = Notifications[notificationConfig];
|
||||||
|
|
||||||
|
// this should _never_ appear on production version of the extension, but it should help with development.
|
||||||
|
if (!config) {
|
||||||
|
return this.vuexStore?.dispatch('uw-set-notification', {
|
||||||
|
icon: 'x-circle-fill',
|
||||||
|
text: `Notification for key ${notificationConfig} does not exist.`,
|
||||||
|
timeout: -1,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't show notification if it's muted
|
||||||
|
if (this.isNotificationMuted(notificationConfig)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.vuexStore?.dispatch('uw-set-notification', {
|
||||||
|
...config,
|
||||||
|
hideActions: [
|
||||||
|
{
|
||||||
|
command: () => this.muteNotification(notificationConfig, MuteScope.CurrentSite),
|
||||||
|
label: 'this site'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
command: () => this.muteNotification(notificationConfig, MuteScope.Global),
|
||||||
|
label: 'never ever'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.error('theres been an error:', e)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.vuexStore?.dispatch('uw-set-notification', notificationConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
muteNotification(notificationId, scope) {
|
||||||
|
// ensure objects we try to set exist
|
||||||
|
if (!this.settings.active.mutedNotifications) {
|
||||||
|
this.settings.active.mutedNotifications = {};
|
||||||
|
}
|
||||||
|
if (!this.settings.active.mutedNotifications[notificationId]) {
|
||||||
|
this.settings.active.mutedNotifications[notificationId] = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// actually mute notification
|
||||||
|
if (scope === MuteScope.Global) {
|
||||||
|
this.settings.active.mutedNotifications[notificationId].$global = true;
|
||||||
|
} else {
|
||||||
|
this.settings.active.mutedNotifications[notificationId][window.location.hostname] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// persist settings
|
||||||
|
this.settings.saveWithoutReload();
|
||||||
|
}
|
||||||
|
|
||||||
|
isNotificationMuted(notificationId) {
|
||||||
|
return this.settings.active.mutedNotifications?.[notificationId]?.$global
|
||||||
|
|| this.settings.active.mutedNotifications?.[notificationId]?.[window.location.hostname];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,19 +38,12 @@ class UI {
|
|||||||
|
|
||||||
async initUi() {
|
async initUi() {
|
||||||
const random = Math.round(Math.random() * 69420);
|
const random = Math.round(Math.random() * 69420);
|
||||||
// const uwid = `uw-${this.interfaceId}-root-${random}`
|
const uwid = `uw-${this.interfaceId}-root-${random}`
|
||||||
const uwid = 'not-so-random-id'
|
|
||||||
|
|
||||||
const rootDiv = document.createElement('div');
|
const rootDiv = document.createElement('div');
|
||||||
|
|
||||||
try {
|
rootDiv.setAttribute('style', `position: ${this.uiConfig.style?.position ?? 'relative'}; width: ${this.uiConfig.style?.width ?? '100%'}; height: ${this.uiConfig.style?.height ?? '100%'}; ${this.uiConfig.additionalStyle ?? ''}`);
|
||||||
rootDiv.setAttribute('style', `position: ${this.uiConfig.style?.position ?? 'relative'}; width: ${this.uiConfig.style?.width ?? '100%'}; height: ${this.uiConfig.style?.height ?? '100%'}; ${this.uiConfig.additionalStyle ?? ''}`);
|
rootDiv.setAttribute('id', uwid);
|
||||||
rootDiv.setAttribute('id', uwid);
|
|
||||||
} catch (e) {
|
|
||||||
console.error("ERROR:", e)
|
|
||||||
}
|
|
||||||
|
|
||||||
console.warn('UI: init 3', this.uiConfig);
|
|
||||||
|
|
||||||
|
|
||||||
if (this.uiConfig?.parentElement) {
|
if (this.uiConfig?.parentElement) {
|
||||||
|
@ -44,7 +44,7 @@ class PlayerData {
|
|||||||
this.extensionMode = videoData.extensionMode;
|
this.extensionMode = videoData.extensionMode;
|
||||||
this.invalid = false;
|
this.invalid = false;
|
||||||
this.element = this.getPlayer();
|
this.element = this.getPlayer();
|
||||||
this.notificationService = new PlayerNotificationUi(this.element);
|
this.notificationService = new PlayerNotificationUi(this.element, this.settings);
|
||||||
this.dimensions = undefined;
|
this.dimensions = undefined;
|
||||||
this.overlayNode = undefined;
|
this.overlayNode = undefined;
|
||||||
|
|
||||||
@ -65,6 +65,7 @@ class PlayerData {
|
|||||||
this.checkPlayerSizeChange();
|
this.checkPlayerSizeChange();
|
||||||
}
|
}
|
||||||
this.startChangeDetection();
|
this.startChangeDetection();
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('[Ultrawidify::PlayerData::ctor] There was an error setting up player data. You should be never seeing this message. Error:', e);
|
console.error('[Ultrawidify::PlayerData::ctor] There was an error setting up player data. You should be never seeing this message. Error:', e);
|
||||||
this.invalid = true;
|
this.invalid = true;
|
||||||
@ -472,6 +473,10 @@ class PlayerData {
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showNotification(notificationId) {
|
||||||
|
this.notificationService?.showNotification(notificationId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process.env.CHANNEL !== 'stable'){
|
if (process.env.CHANNEL !== 'stable'){
|
||||||
|
Loading…
Reference in New Issue
Block a user