Finish notification system (for now)

This commit is contained in:
Tamius Han 2020-12-05 03:30:43 +01:00
parent 12b15c58f8
commit 0310e1e2de
5 changed files with 197 additions and 34 deletions

View 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;

View File

@ -5,11 +5,10 @@
<Icon
class="flex-nogrow flex-noshrink"
:icon="notificationIcon"
@click="closeNotification()"
>
</Icon>
</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
class="notification-text"
v-html="notificationText"
@ -21,18 +20,41 @@
>
<div
v-for="action of notificationActions"
class="action-button"
:key="action"
@click="action.command"
>
<Icon v-if="action.icon" :icon="action.icon"></Icon>{{action.label}}
</div>
</div>
<div
v-if="hideActions"
class="hide-actions"
>
Never show again:<wbr>&nbsp;
<template
v-for="action of hideActions"
:key="action"
>
<i @click="closeNotification">
<a
class="hide-action-button"
@click="action.command"
>
{{action.label}}
</a>
<wbr>&nbsp;
</i>
</template>
</div>
</div>
<div class="notification-icon">
<div
class="notification-icon action-button"
@click="closeNotification()"
>
<Icon
class="flex-nogrow flex-noshrink"
icon="x"
@click="closeNotification()"
>
</Icon>
</div>
@ -50,20 +72,19 @@ export default {
},
data() {
return {
// notificationIcon: null,
// notificationText: null,
// notificationActions: null,
// showNotification: false,
notificationTimeout: null,
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,
showNotification: true,
hideActions: null,
showNotification: false,
};
},
...mapState([
'notificationConfig'
]),
computed: {
...mapState([
'notificationConfig'
]),
},
watch: {
/**
* 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
* icon: icon of the button
* }
* ],
* hideOptions: [
* // more of notificationActions except it's a special case
* ]
* }
*/
notificationConfig(newConfig) {
console.log('notificationConfig?');
if (newConfig) {
this.notificationText = newConfig.text;
this.notificationActions = newConfig.notificationActions;
this.notificationIcon = newConfig.icon;
this.hideActions = newConfig.hideActions;
this.showNotification = true;
if (newConfig.timeout !== -1) {
this.notificationTimeout = setTimeout(() => this.closeNotification(), newConfig.timeout ?? 10000);
this.notificationTimeout = setTimeout(() => this.closeNotification(), newConfig.timeout ?? 5000);
}
}
}
},
methods: {
closeNotification() {
console.log("close notification!")
clearTimeout(this.notificationTimeout);
this.showNotification = false;
this.notificationIcon = null;
this.notificationText = null;
this.notificationActions = null;
this.hideActions = null;
}
}
}
@ -120,18 +149,62 @@ export default {
position: relative;
width: 100%;
height: 100%;
pointer-events: none;
font-size: 16px;
.notification-popup {
pointer-events: auto !important;
position: absolute;
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);
top: 2rem;
left: 2rem;
width: 15rem;
color: #fff;
user-select: none;
}
.notifcation-content {
margin-left: 0.5em;
}
.notification-text {
text-align: justify;
}
.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>

View File

@ -1,23 +1,31 @@
import UI from './UI';
import VuexWebExtensions from 'vuex-webextensions';
import NotificationUi from '../../../csui/NotificationUi.vue';
import Notifications from '../../../common/data/notifications';
if (process.env.CHANNEL !== 'stable'){
console.info("Loading: PlayerNotificationUi");
}
let MuteScope = Object.freeze({
CurrentSite: 'current-site',
Global: 'global'
});
class PlayerNotificationUi extends UI {
constructor (
playerElement
) {
playerElement,
settings
) {
super(
'notification',
PlayerNotificationUi.getStoreConfig(),
PlayerNotificationUi.getUiConfig(playerElement),
PlayerNotificationUi.getCommsConfig()
)
);
this.settings = settings;
}
@ -42,11 +50,13 @@ class PlayerNotificationUi extends UI {
},
mutations: {
'uw-set-notification'(state, payload) {
console.log('mutation!', state, payload);
state['notificationConfig'] = payload;
}
},
actions: {
'uw-set-notification'({commit}, payload) {
console.log('action!', commit, payload);
commit('uw-set-notification', payload);
}
}
@ -78,7 +88,7 @@ class PlayerNotificationUi extends UI {
/**
* 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:
* {
@ -91,11 +101,79 @@ class PlayerNotificationUi extends UI {
* label: label 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) {
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];
}
}

View File

@ -38,19 +38,12 @@ class UI {
async initUi() {
const random = Math.round(Math.random() * 69420);
// const uwid = `uw-${this.interfaceId}-root-${random}`
const uwid = 'not-so-random-id'
const uwid = `uw-${this.interfaceId}-root-${random}`
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('id', uwid);
} catch (e) {
console.error("ERROR:", e)
}
console.warn('UI: init 3', this.uiConfig);
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);
if (this.uiConfig?.parentElement) {

View File

@ -44,7 +44,7 @@ class PlayerData {
this.extensionMode = videoData.extensionMode;
this.invalid = false;
this.element = this.getPlayer();
this.notificationService = new PlayerNotificationUi(this.element);
this.notificationService = new PlayerNotificationUi(this.element, this.settings);
this.dimensions = undefined;
this.overlayNode = undefined;
@ -65,6 +65,7 @@ class PlayerData {
this.checkPlayerSizeChange();
}
this.startChangeDetection();
} catch (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;
@ -472,6 +473,10 @@ class PlayerData {
return true;
}
showNotification(notificationId) {
this.notificationService?.showNotification(notificationId);
}
}
if (process.env.CHANNEL !== 'stable'){