FreeDATA/gui/src/components/chat_new_message.vue

356 lines
10 KiB
Vue
Raw Normal View History

2023-09-21 12:17:03 +00:00
<script setup lang="ts">
// @ts-nocheck
2023-09-21 12:17:03 +00:00
import { setActivePinia } from 'pinia';
import pinia from '../store/index';
setActivePinia(pinia);
import { useStateStore } from '../store/stateStore.js';
const state = useStateStore(pinia);
import { useChatStore } from '../store/chatStore.js';
const chat = useChatStore(pinia);
import chat_navbar from './chat_navbar.vue'
import chat_conversations from './chat_conversations.vue'
import chat_messages from './chat_messages.vue'
import { newMessage } from '../js/messagesHandler.ts'
2023-09-21 12:17:03 +00:00
2023-10-04 20:12:51 +00:00
import {
Chart as ChartJS,
CategoryScale,
LinearScale,
PointElement,
LineElement,
Title,
Tooltip,
Legend
} from 'chart.js'
import { Line } from 'vue-chartjs'
import { ref, computed } from 'vue';
2023-09-21 12:17:03 +00:00
2023-10-19 14:54:24 +00:00
import { VuemojiPicker, EmojiClickEventDetail } from 'vuemoji-picker'
const handleEmojiClick = (detail: EmojiClickEventDetail) => {
chat.inputText += detail.unicode
}
const chatModuleMessage=ref(null);
2023-09-21 12:17:03 +00:00
// Function to trigger the hidden file input
function triggerFileInput() {
fileInput.value.click();
}
2023-10-19 14:54:24 +00:00
// Use a ref for storing multiple files
const selectedFiles = ref([]);
const fileInput = ref(null);
function handleFileSelection(event) {
// Reset previously selected files
selectedFiles.value = [];
// Process each file
for (let file of event.target.files) {
const reader = new FileReader();
reader.onload = () => {
// Convert file content to base64
const base64Content = btoa(reader.result); // Adjust this line if necessary
selectedFiles.value.push({
name: file.name,
size: file.size,
type: file.type,
content: base64Content, // Store base64 encoded content
});
};
reader.readAsBinaryString(file); // Read the file content as binary string
}
2024-02-06 19:20:52 +00:00
}
2024-02-06 20:05:57 +00:00
function removeFile(index) {
selectedFiles.value.splice(index, 1);
}
2024-02-06 19:20:52 +00:00
function transmitNewMessage() {
// Check if a callsign is selected, default to the first one if not
if (typeof(chat.selectedCallsign) === 'undefined') {
2024-02-03 11:09:57 +00:00
chat.selectedCallsign = Object.keys(chat.callsign_list)[0];
}
chat.inputText = chat.inputText.trim();
2023-09-27 14:55:57 +00:00
// Proceed only if there is text or files selected
if (chat.inputText.length === 0 && selectedFiles.value.length === 0) return;
2023-09-27 14:55:57 +00:00
const attachments = selectedFiles.value.map(file => {
return {
name: file.name,
type: file.type,
data: file.content
};
});
if (chat.selectedCallsign.startsWith("BC-")) {
// Handle broadcast message differently if needed
return "new broadcast";
2023-09-27 14:55:57 +00:00
} else {
// If there are attachments, send them along with the message
if (attachments.length > 0) {
newMessage(chat.selectedCallsign, chat.inputText, attachments);
} else {
// Send text only if no attachments are selected
newMessage(chat.selectedCallsign, chat.inputText);
}
2023-09-27 14:55:57 +00:00
}
// Cleanup after sending message
chat.inputText = '';
chatModuleMessage.value = "";
2024-02-06 20:05:57 +00:00
resetFile()
2023-09-21 21:04:12 +00:00
}
2023-09-21 12:17:03 +00:00
2023-09-21 21:04:12 +00:00
function resetFile(event){
2024-02-06 20:05:57 +00:00
//fileInput.reset()
fileInput.value = null
2024-02-06 19:20:52 +00:00
// Clear the selected files array to reset the state of attachments
selectedFiles.value = [];
2023-09-21 12:17:03 +00:00
2024-02-06 19:20:52 +00:00
}
2023-09-21 12:17:03 +00:00
ChartJS.register(
CategoryScale,
LinearScale,
PointElement,
LineElement,
Title,
Tooltip,
Legend
)
// calculate time needed for transmitting a file
function calculateTimeNeeded(){
var calculatedSpeedPerMinutePER0 = []
var calculatedSpeedPerMinutePER25 = []
var calculatedSpeedPerMinutePER75 = []
// bpm vs snr with PER == 0
var snrList = [
{snr: -10, bpm: 100},
{snr: -5, bpm: 300},
{snr: 0, bpm: 800},
{snr: 5, bpm: 2500},
{snr: 10, bpm: 5300}
];
for (let i = 0; i < snrList.length; i++) {
var result = snrList.find(obj => {
return obj.snr === snrList[i].snr
})
calculatedSpeedPerMinutePER0.push(totalSize / result.bpm)
calculatedSpeedPerMinutePER25.push(totalSize / (result.bpm * 0.75))
calculatedSpeedPerMinutePER75.push(totalSize / (result.bpm * 0.25))
2023-09-21 12:17:03 +00:00
}
chat.chartSpeedPER0 = calculatedSpeedPerMinutePER0
chat.chartSpeedPER25 = calculatedSpeedPerMinutePER25
chat.chartSpeedPER75 = calculatedSpeedPerMinutePER75
}
const speedChartData = computed(() => ({
labels: ['-10', '-5', '0', '5', '10'],
datasets: [
{ data: chat.chartSpeedPER0, label: 'PER 0%' ,tension: 0.1, borderColor: 'rgb(0, 255, 0)' },
{ data: chat.chartSpeedPER25, label: 'PER 25%' ,tension: 0.1, borderColor: 'rgb(255, 255, 0)'},
{ data: chat.chartSpeedPER75, label: 'PER 75%' ,tension: 0.1, borderColor: 'rgb(255, 0, 0)' }
]
}
));
</script>
<template>
<div class="container-fluid mt-2 p-0">
<input
type="checkbox"
id="expand_textarea"
class="btn-check"
autocomplete="off"
/>
<label
class="btn d-flex justify-content-center"
id="expand_textarea_label"
for="expand_textarea"
><i
id="expand_textarea_button"
class="bi bi-chevron-compact-up"
></i
></label>
<div class="input-group bottom-0 ms-2">
2023-10-19 14:54:24 +00:00
<button type="button" class="btn btn-outline-secondary border-0 rounded-pill me-1"
data-bs-toggle="modal" data-bs-target="#emojiPickerModal"
data-bs-backdrop="false"
>
<i
id="emojipickerbutton"
class="bi bi-emoji-smile p-0"
style="font-size: 1rem"
></i>
</button>
<!-- trigger file selection modal -->
2024-02-06 19:20:52 +00:00
<button type="button" class="btn btn-outline-secondary border-0 rounded-pill me-1" data-bs-toggle="modal" data-bs-target="#fileSelectionModal">
2023-10-19 14:54:24 +00:00
<i class="bi bi-paperclip" style="font-size: 1.2rem"></i>
2024-02-06 19:20:52 +00:00
<!-- Badge showing the number of attached files -->
<span class="badge bg-warning">{{ selectedFiles.length }}</span>
2023-10-19 14:54:24 +00:00
</button>
2023-09-21 12:17:03 +00:00
<textarea
2023-10-19 14:54:24 +00:00
class="form-control border rounded-pill"
2023-09-21 12:17:03 +00:00
rows="1"
ref="chatModuleMessage"
2023-09-21 12:17:03 +00:00
placeholder="Message - Send with [Enter]"
v-model="chat.inputText"
@keyup.enter.exact="transmitNewMessage()"
2023-09-21 12:17:03 +00:00
></textarea>
<button
2023-10-19 14:54:24 +00:00
class="btn btn-sm btn-secondary ms-1 me-2 rounded-pill"
2023-09-21 12:17:03 +00:00
@click="transmitNewMessage()"
type="button"
>
<i
class="bi bi-send ms-4 me-4"
style="font-size: 1.2rem"
></i>
</button>
</div>
</div>
<!-- select file modal -->
<div
class="modal fade"
id="fileSelectionModal"
tabindex="-1"
aria-labelledby="fileSelectionModalLabel"
aria-hidden="true"
>
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="staticBackdropLabel">File Attachment</h5>
2023-09-21 21:04:12 +00:00
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" @click="resetFile"></button>
2023-09-21 12:17:03 +00:00
</div>
<div class="modal-body">
<div class="alert alert-warning d-flex align-items-center" role="alert">
<i class="bi bi-exclamation-triangle-fill ms-2 me-2"></i>
<div>
2023-09-21 21:04:12 +00:00
Transmission speed over HF channels is very limited!
2023-09-21 12:17:03 +00:00
</div>
</div>
2023-09-21 12:17:03 +00:00
<div class="container w-100 mb-3">
<!-- Button that user will click to open file dialog -->
<button class="btn btn-primary w-100" @click="triggerFileInput">Attach Files</button>
2023-09-21 12:17:03 +00:00
<!-- Hidden file input -->
<input type="file" multiple ref="fileInput" @change="handleFileSelection" style="display: none;" />
2024-02-06 20:05:57 +00:00
</div>
<div class="container-fluid px-0">
<div class="d-flex flex-row overflow-auto bg-light rounded-3 p-2 border border-1">
<div v-for="(file, index) in selectedFiles" :key="index" class="pe-2">
<div class="card" style=" min-width: 10rem; max-width: 10rem;">
<!-- Card Header with Remove Button -->
<div class="card-header d-flex justify-content-between align-items-center">
<span class="text-truncate">{{ file.name }}</span>
<button class="btn btn-close" @click="removeFile(index)"></button>
</div>
<div class="card-body">
<p class="card-text">...</p>
</div>
<div class="card-footer text-muted">
{{ file.type }}
</div>
<div class="card-footer text-muted">
{{ file.size }} bytes
</div>
</div>
</div>
</div>
</div>
2024-02-06 19:20:52 +00:00
<!--
2023-10-22 12:49:33 +00:00
<Line :data="speedChartData" />
2024-02-06 19:20:52 +00:00
-->
2023-09-21 12:17:03 +00:00
</div>
<div class="modal-footer">
2023-09-21 21:04:12 +00:00
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" @click="resetFile">Reset</button>
<button type="button" class="btn btn-primary" data-bs-dismiss="modal">Append</button>
2023-09-21 12:17:03 +00:00
</div>
</div>
</div>
</div>
2023-10-19 14:54:24 +00:00
<!-- Emoji Picker Modal -->
<div class="modal fade" id="emojiPickerModal" tabindex="-1" aria-hidden="true">
2023-10-20 11:47:42 +00:00
<div class="modal-dialog modal-dialog-centered modal-sm">
2023-10-19 14:54:24 +00:00
<div class="modal-content">
<div class="modal-body p-0">
<VuemojiPicker @emojiClick="handleEmojiClick" />
</div>
</div>
</div>
</div>
</template>
2023-09-21 12:17:03 +00:00