Initial commit
This commit is contained in:
123
fusion_notes/static/src/xml/voice_note_button.xml
Normal file
123
fusion_notes/static/src/xml/voice_note_button.xml
Normal file
@@ -0,0 +1,123 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!--
|
||||
Fusion Notes - Chatter Voice Note Templates
|
||||
Copyright 2026 Nexa Systems Inc.
|
||||
License OPL-1
|
||||
|
||||
Extends the mail.Chatter template to add:
|
||||
1. A microphone button in the topbar (idle / recording / transcribing states)
|
||||
2. A review panel below the topbar for editing before posting
|
||||
|
||||
All styling uses Bootstrap/Odoo utility classes so the component
|
||||
follows the active theme (light, dark, or custom) automatically.
|
||||
-->
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<!-- Extend Chatter to inject voice note UI -->
|
||||
<t t-inherit="mail.Chatter" t-inherit-mode="extension">
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- 1. Mic button / recording controls in the topbar -->
|
||||
<!-- Inserted right after the "Log note" button -->
|
||||
<!-- ============================================================ -->
|
||||
<xpath expr="//button[hasclass('o-mail-Chatter-logNote')]" position="after">
|
||||
|
||||
<!-- IDLE: Microphone button -->
|
||||
<button t-if="state.voiceStatus === 'idle'"
|
||||
class="o-mail-Chatter-voiceNote btn text-nowrap me-1 fusion-notes-mic-btn"
|
||||
t-att-class="{
|
||||
'btn-primary': state.composerType === 'note',
|
||||
'btn-secondary': state.composerType !== 'note',
|
||||
'my-2': !props.compactHeight
|
||||
}"
|
||||
t-att-disabled="isDisabled"
|
||||
t-on-click="voiceStartRecording"
|
||||
title="Record voice note">
|
||||
<i class="fa fa-microphone"/>
|
||||
</button>
|
||||
|
||||
<!-- RECORDING: Stop button + pulsing indicator + timer -->
|
||||
<div t-if="state.voiceStatus === 'recording'"
|
||||
class="d-flex align-items-center me-1 fusion-notes-recording"
|
||||
t-att-class="{ 'my-2': !props.compactHeight }">
|
||||
<button class="btn btn-danger btn-sm me-1 px-2"
|
||||
t-on-click="voiceStopRecording"
|
||||
title="Stop recording">
|
||||
<i class="fa fa-stop"/>
|
||||
</button>
|
||||
<span class="fusion-notes-pulse me-1"/>
|
||||
<span class="text-danger fw-bold small"
|
||||
t-esc="voiceFormatDuration(state.voiceDuration)"/>
|
||||
<button class="btn btn-link btn-sm opacity-75 opacity-100-hover ms-1 p-0"
|
||||
t-on-click="voiceCancelRecording"
|
||||
title="Cancel recording">
|
||||
<i class="fa fa-times"/>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- TRANSCRIBING / FORMATTING: Spinner -->
|
||||
<div t-if="state.voiceStatus === 'transcribing' || state.voiceStatus === 'formatting'"
|
||||
class="d-flex align-items-center me-1"
|
||||
t-att-class="{ 'my-2': !props.compactHeight }">
|
||||
<i class="fa fa-spinner fa-spin me-1 opacity-75"/>
|
||||
<span class="small opacity-75"
|
||||
t-if="state.voiceStatus === 'transcribing'">Transcribing...</span>
|
||||
<span class="small opacity-75"
|
||||
t-if="state.voiceStatus === 'formatting'">Formatting...</span>
|
||||
</div>
|
||||
|
||||
</xpath>
|
||||
|
||||
<!-- ============================================================ -->
|
||||
<!-- 2. Review panel below topbar (before the normal Composer) -->
|
||||
<!-- ============================================================ -->
|
||||
<xpath expr="//div[hasclass('o-mail-Chatter-topbar')]" position="after">
|
||||
|
||||
<div t-if="state.voiceStatus === 'review'" class="fusion-notes-review">
|
||||
<!-- Header row -->
|
||||
<div class="d-flex align-items-center justify-content-between px-3 pt-2 pb-1">
|
||||
<span class="fw-bold small">
|
||||
<i class="fa fa-microphone me-1"/>Voice Note
|
||||
</span>
|
||||
<div class="d-flex align-items-center gap-1">
|
||||
<button class="btn btn-sm"
|
||||
t-att-class="state.voiceAiFormat ? 'btn-primary' : 'btn-light border'"
|
||||
t-on-click="voiceToggleAiFormat"
|
||||
title="Toggle AI formatting">
|
||||
<i class="fa fa-magic me-1"/>AI Format
|
||||
</button>
|
||||
<button class="btn btn-sm btn-light border"
|
||||
t-on-click="voiceCancelNote"
|
||||
title="Cancel">
|
||||
<i class="fa fa-times"/>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Text area -->
|
||||
<div class="px-3 pb-2">
|
||||
<textarea class="form-control fusion-notes-textarea"
|
||||
t-att-value="state.voiceText"
|
||||
t-on-input="onVoiceTextInput"
|
||||
rows="3"
|
||||
placeholder="Transcribed text will appear here..."/>
|
||||
<div class="d-flex align-items-center justify-content-between mt-2">
|
||||
<div class="small opacity-75">
|
||||
<span t-if="state.voiceAiFormat"
|
||||
class="badge rounded-pill text-bg-info me-1">AI Formatted</span>
|
||||
<span t-else=""
|
||||
class="badge rounded-pill text-bg-light border me-1">Raw Transcription</span>
|
||||
</div>
|
||||
<button class="btn btn-primary btn-sm"
|
||||
t-on-click="voicePostNote">
|
||||
<i class="fa fa-paper-plane me-1"/>Post Note
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</xpath>
|
||||
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
Reference in New Issue
Block a user