Initial commit: OCA Technical packages (595 packages)

This commit is contained in:
Ernad Husremovic 2025-08-29 15:43:03 +02:00
commit 2cc02aac6e
24950 changed files with 2318079 additions and 0 deletions

View file

@ -0,0 +1,70 @@
/** @odoo-module alias=web_notify.AudioPlayer **/
import {Component, useState} from "@odoo/owl";
/**
* @typedef AudioPlayerProps
* @property {string} src URL of the audio file to be played
* @property {number} [volume=1.0] Volume level of the audio (from 0.0 to 1.0)
* @property {boolean} [loop=false] Whether the audio should loop
* @property {Function} [onEnded] Callback function to be called when the audio ends
*/
/**
* The AudioPlayer component is responsible for playing audio files with
* specified settings like volume and looping. It also provides the ability
* to trigger actions when the audio playback ends.
*/
export class AudioPlayer extends Component {
setup() {
this.state = useState({isPlaying: false});
this.audioElement = new Audio(this.props.src);
// Set audio properties
this.audioElement.volume = this.props.volume || 1.0;
this.audioElement.loop = this.props.loop || false;
// Start playing the audio
this.audioElement
.play()
.then(() => {
this.state.isPlaying = true;
})
.catch((error) => {
console.error("Audio playback failed:", error);
});
// Listen for the end of the audio playback
this.audioElement.addEventListener("ended", this.onAudioEnded.bind(this));
}
/**
* Stops the audio playback and triggers the onEnded callback if provided.
*/
stopAudio() {
this.audioElement.pause();
this.audioElement.currentTime = 0;
this.state.isPlaying = false;
if (this.props.onEnded) {
this.props.onEnded();
}
}
/**
* Handler for when the audio playback ends.
*/
onAudioEnded() {
if (!this.props.loop) {
this.stopAudio();
}
}
willUnmount() {
// Clean up the audio element and listeners
this.audioElement.removeEventListener("ended", this.onAudioEnded);
this.audioElement.pause();
}
}
AudioPlayer.template = "web_notify.AudioPlayer";

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!-- Copyright 2024 Cetmix OÜ
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<templates xml:space="preserve">
<t t-name="web_notify.AudioPlayer" owl="1">
<!-- No visual elements needed, audio is controlled programmatically -->
</t>
</templates>

View file

@ -0,0 +1,12 @@
/** @odoo-module */
import {Notification} from "@web/core/notifications/notification";
import {patch} from "web.utils";
patch(Notification.props, "webNotifyProps", {
type: {
type: String,
optional: true,
validate: (t) =>
["warning", "danger", "success", "info", "default"].includes(t),
},
});

View file

@ -0,0 +1,70 @@
/** @odoo-module **/
import {Markup} from "web.utils";
import {browser} from "@web/core/browser/browser";
import {registry} from "@web/core/registry";
export const webNotificationService = {
dependencies: ["bus_service", "action", "notification_sound"],
start(env, {bus_service, action, notification_sound}) {
let webNotifTimeouts = {};
/**
* Displays the web notification with sound on user's screen
* @param {*} notifications
*/
function displaywebNotification(notifications) {
Object.values(webNotifTimeouts).forEach((notif) =>
browser.clearTimeout(notif)
);
webNotifTimeouts = {};
notifications.forEach((notif) => {
browser.setTimeout(() => {
var buttons = [];
if (notif.action) {
const params =
(notif.action.context && notif.action.context.params) || {};
buttons = [
{
name: params.button_name || env._t("Open"),
primary: true,
onClick: async () => {
await action.doAction(notif.action);
},
...(params.button_icon && {icon: params.button_icon}),
},
];
}
const notificationRemove = notification_sound.add(
Markup(notif.message),
{
title: notif.title,
type: notif.type,
sticky: notif.sticky,
className: notif.className,
buttons: buttons.map((button) => {
const onClick = button.onClick;
button.onClick = async () => {
await onClick();
notificationRemove();
};
return button;
}),
sound: notif.sound,
}
);
});
});
}
bus_service.addEventListener("notification", ({detail: notifications}) => {
for (const {payload, type} of notifications) {
if (type === "web.notify") {
displaywebNotification(payload);
}
}
});
bus_service.start();
},
};
registry.category("services").add("webNotification", webNotificationService);

View file

@ -0,0 +1,43 @@
/** @odoo-module **/
import {registry} from "@web/core/registry";
import {AudioPlayer} from "../components/audio_player.esm";
const effectRegistry = registry.category("effects");
// -----------------------------------------------------------------------------
// Audio effect
// -----------------------------------------------------------------------------
/**
* Handles effect of type "audio_effect". It returns the AudioPlayer component
* with the given audio source URL and other properties.
*
* @param {Object} env
* @param {Object} [params={}]
* @param {string} params.src
* The URL of the audio file to play.
* @param {number} [params.volume=1.0] Volume level of the audio (from 0.0 to 1.0)
* @param {boolean} [params.loop=false] Whether the audio should loop
* @param {Function} [params.onEnded] Callback function to be called when the audio ends
*/
function audioEffect(env, params = {}) {
if (!params.src) {
console.warn(
"Audio effect requires a 'src' parameter with the URL of the audio file."
);
return;
}
return {
Component: AudioPlayer,
props: {
src: params.src,
volume: params.volume || 1.0,
loop: params.loop || false,
onEnded: params.onEnded,
},
};
}
effectRegistry.add("audio_effect", audioEffect);

View file

@ -0,0 +1,58 @@
/** @odoo-module **/
import {registry} from "@web/core/registry";
/**
* The notificationSoundService is responsible for handling the playback of audio
* notifications when a new notification is added. This service integrates with
* the notification system and the effect service to provide audible feedback
* based on the type of notification.
*
* Dependencies:
* - notification: The service responsible for displaying notifications on the UI.
* - effect: The service that handles visual and auditory effects in the application.
*/
export const notificationSoundService = {
dependencies: ["notification", "effect"],
/**
* Starts the notification sound service, enabling sound playback for notifications.
*
* @param {Object} env The environment object, providing access to various services.
* @param {Object} services An object containing the dependencies (notification, effect).
* @returns {Object} The add function, used to add notifications with sound.
*/
start(env, {notification, effect}) {
/**
* Adds a notification with an associated sound effect.
*
* @param {String} message The message to be displayed in the notification.
* @param {Object} [options={}] Additional options for the notification, such as type, sound and etc
* @returns {Function} A function to close the notification.
*/
function add(message, options = {}) {
const sound = options.sound || false;
delete options.sound; // Remove sound option from the options before passing to notification
const closeFn = notification.add(message, options);
if (sound)
// Trigger the audio effect.
effect.add({
type: "audio_effect",
src: sound,
volume: 0.8,
loop: false,
onEnded: () => {
// Placeholder for any action after sound ends
},
});
return closeFn;
}
return {add};
},
};
// Register the notification sound service in the service registry
registry.category("services").add("notification_sound", notificationSoundService);