add classes for notification UI.
The UI classes are split into "general UI" part — a base class that could potentially be used for proper in-player UI if we ever get to that point — and part that's specific to our notification requirements.
This commit is contained in:
parent
55fbd30699
commit
38641df28e
98
src/ext/lib/uwui/PlayerNotificationUI.js
Normal file
98
src/ext/lib/uwui/PlayerNotificationUI.js
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
import UI from './UI';
|
||||||
|
import VuexWebExtensions from 'vuex-webextensions';
|
||||||
|
import VideoNotification from '../../../csui/VideoNotification';
|
||||||
|
|
||||||
|
class PlayerNotification extends UI {
|
||||||
|
|
||||||
|
constructor (
|
||||||
|
playerElement
|
||||||
|
) {
|
||||||
|
|
||||||
|
super(
|
||||||
|
'notification',
|
||||||
|
getStoreConfig(),
|
||||||
|
getUiConfig(playerElement),
|
||||||
|
getCommsConfig()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//#region constructor helpers
|
||||||
|
// we will move some things out of the constructor in order to keep things clean
|
||||||
|
getStoreConfig() {
|
||||||
|
return {
|
||||||
|
plugins: [
|
||||||
|
VuexWebExtensions({
|
||||||
|
persistentStates: [
|
||||||
|
'notificationConfig'
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
state: {
|
||||||
|
// should be null by default!
|
||||||
|
notificationConfig: {
|
||||||
|
text: 'sample text <b>now with 100% more html formatting!</b>',
|
||||||
|
icon: 'exclamation-circle',
|
||||||
|
timeout: 5000,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mutations: {
|
||||||
|
'uw-set-notification'(state, payload) {
|
||||||
|
state['notificationConfig'] = payload;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
'uw-set-notification'({commit}, payload) {
|
||||||
|
commit('uw-set-notification', payload);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
getUiConfig(playerElement) {
|
||||||
|
return {
|
||||||
|
parentElement: playerElement,
|
||||||
|
component: VideoNotification
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getCommsConfig() {
|
||||||
|
return {
|
||||||
|
handlers = {
|
||||||
|
'show-notification': [(message) => this.showNotification(message)],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
//#region lifecycle
|
||||||
|
replace(playerElement) {
|
||||||
|
super.replace(this.getUiConfig(playerElement));
|
||||||
|
}
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show notification on screen.
|
||||||
|
*
|
||||||
|
* @param notificationConfig notification config
|
||||||
|
*
|
||||||
|
* notificationConfig should resemble this:
|
||||||
|
* {
|
||||||
|
* timeout: number — how long we'll be displaying the notification. If empty, 10s. -1: until user dismisses it
|
||||||
|
* icon: string — what icon we're gonna show. We're using bootstrap icons. Can be empty.
|
||||||
|
* text: — notification text. Supports HTML.
|
||||||
|
* notificationActions: [
|
||||||
|
* {
|
||||||
|
* command: function that gets executed upon clicking the button.
|
||||||
|
* label: label of the button
|
||||||
|
* icon: icon of the button
|
||||||
|
* }
|
||||||
|
* ]
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
showNotification(notificationConfig) {
|
||||||
|
this.vuexStore?.dispatch('uw-set-notification', notificationConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PlayerNotification;
|
76
src/ext/lib/uwui/UI.js
Normal file
76
src/ext/lib/uwui/UI.js
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
import { createApp } from 'vue';
|
||||||
|
import { createStore } from 'vuex';
|
||||||
|
|
||||||
|
class UI {
|
||||||
|
constructor(
|
||||||
|
interfaceId,
|
||||||
|
storeConfig,
|
||||||
|
uiConfig, // {component, parentElement?}
|
||||||
|
commsConfig,
|
||||||
|
) {
|
||||||
|
this.interfaceId = interfaceId;
|
||||||
|
this.commsConfig = commsConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
async init() {
|
||||||
|
// If comms exist, we need to destroy it
|
||||||
|
if (this.comms) {
|
||||||
|
this.comms.destroy();
|
||||||
|
}
|
||||||
|
if (!this.settings) {
|
||||||
|
this.settings = new Settings({
|
||||||
|
onSettingsChanged: () => this.reloadSettings(),
|
||||||
|
logger: this.logger
|
||||||
|
});
|
||||||
|
await this.settings.init();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.comms = new CommsClient('content-ui-port', null, this.commsConfig.handlers);
|
||||||
|
|
||||||
|
// initialize vuejs, but only once (check handled in initVue())
|
||||||
|
// we need to initialize this _after_ initializing comms.
|
||||||
|
this.initVue();
|
||||||
|
}
|
||||||
|
|
||||||
|
async initVue() {
|
||||||
|
this.vuexStore = createStore(this.storeConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
async initUi() {
|
||||||
|
const random = Math.round(Math.random() * 69420);
|
||||||
|
const uwid = `uw-${this.interfaceId}-root-${random}`
|
||||||
|
|
||||||
|
const rootDiv = document.createElement('div');
|
||||||
|
rootDiv.setAttribute('style', `position: ${uiConfig.style?.position ?? 'relative'}; width: ${uiConfig.style?.width ?? '100%'}; height: ${uiConfig.style?.height ?? '100%'}; ${uiConfig.additionalStyle}`);
|
||||||
|
rootDiv.setAttribute('id', uwid);
|
||||||
|
|
||||||
|
if (this.uiConfig.parentElement) {
|
||||||
|
this.uiConfig.parentElement.appendChild(rootDiv);
|
||||||
|
} else {
|
||||||
|
document.body.appendChild(rootDiv);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.element = rootDiv;
|
||||||
|
|
||||||
|
createApp(this.uiConfig.component)
|
||||||
|
.use(this.vuexStore)
|
||||||
|
.mount(`${uwid}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces ui config and re-inits the UI
|
||||||
|
* @param {*} newUiConfig
|
||||||
|
*/
|
||||||
|
replace(newUiConfig) {
|
||||||
|
this.element?.remove();
|
||||||
|
this.uiConfig = newUiConfig;
|
||||||
|
this.initUi();
|
||||||
|
}
|
||||||
|
|
||||||
|
destroy() {
|
||||||
|
this.comms?.destroy();
|
||||||
|
this.element?.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default UI;
|
Loading…
Reference in New Issue
Block a user