mindboost-rnbo-test-project/pages/onboarding/onboarding1.vue

192 lines
5.8 KiB
Vue

<template>
<div>
<div class="row text-center">
<div class="col-12">
<h1 class="h3 fw-bold mb-4">
{{ t("How is your audio hardware connected?") }}
</h1>
<p class="text-muted mx-auto">
{{ t('Onboarding-input') }}<br>
{{ t('Onboarding-output') }}
</p>
</div>
</div>
<div class="row justify-content-center pt-4">
<div class="col-11">
<form v-if="!loading">
<div class="row justify-content-center mb-4">
<div class="col-md-5 text-center">
<label for="inputSelect" class="fw-semibold">{{ t('Input device:') }}</label>
<p class="pt-0 mt-0 text-muted pb-2 mb-0" style="font-size: 14px;font-weight: 500">
({{ t('select laptop or mobile device microphone') }})
</p>
<select id="inputSelect" v-model="selectedInput" class="form-select pt-1 mt-0 select-box" @change="checkIfSameDevice">
<option v-for="(item,index) in audioInputDevices" :key="index" :value="index">
{{ item.label || `Eingabegerät ${index + 1}` }}
</option>
</select>
</div>
</div>
<div class="row justify-content-center mb-4">
<div class="col-md-5 text-center">
<label for="outputSelect" class="fw-semibold">{{ t('Output device:') }}</label>
<p class="pt-0 mt-0 text-muted pb-0 mb-0" style="font-size: 14px;font-weight: 500">
{{ t('select headphones or headphone output') }}
</p>
<select id="outputSelect" v-model="selectedOutput" class="form-select pt-1 mt-0 select-box" @change="checkIfSameDevice">
<option v-for="(item,index) in audioOutputDevices" :key="index" :value="index">
{{ item.label || `Ausgabegerät ${index + 1}` }}
</option>
</select>
</div>
</div>
<div class="row justify-content-center pt-4">
<div class="col-md-3 text-center" style="z-index: 1000000;">
<button
type="button"
class="btn col-4 btn-primary-custom"
:disabled="audioInputDevices.length === 0 || audioOutputDevices.length === 0"
@click.prevent="saveDevices"
>
{{ t("Next") }}
</button>
</div>
</div>
</form>
<div v-else class="text-center">
<p>Lade Geräte...</p>
</div>
</div>
</div>
</div>
</template>
<script>
import { mapState, mapActions } from 'pinia'
import { useUserStore } from '~/stores/user'
export default {
emits: ['next-step'],
setup () {
const { t } = useI18n()
const localePath = useLocalePath()
return {
t,
localePath
}
},
data () {
return {
loading: true,
audioInputDevices: [],
audioOutputDevices: [],
selectedInput: null,
selectedOutput: null,
stream: null
}
},
computed: {
...mapState(useUserStore, ['audioInputDevice', 'audioOutputDevice'])
},
async created () {
try {
// Zuerst Media-Zugriff einholen (sonst keine Labels)
await this.getUserMedia()
const devices = await navigator.mediaDevices.enumerateDevices()
this.audioInputDevices = devices.filter(d => d.kind === 'audioinput')
this.audioOutputDevices = devices.filter(d => d.kind === 'audiooutput')
// Setze Indexe basierend auf gespeicherten IDs
this.selectedInput = this.audioInputDevices.findIndex(d => d.deviceId === this.audioInputDevice.deviceId)
this.selectedOutput = this.audioOutputDevices.findIndex(d => d.deviceId === this.audioOutputDevice.deviceId)
// Fallback auf erstes Gerät
if (this.selectedInput < 0) { this.selectedInput = 0 }
if (this.selectedOutput < 0) { this.selectedOutput = 0 }
// Warnung, wenn gleiche Geräte gewählt sind
if (this.checkIfSameDevice()) {
this.$toast.warning(this.t('bluetoothWarning'), {
duration: 6000,
pauseOnHover: true,
dismissible: true,
queue: true,
position: 'bottom-left'
})
}
} catch (error) {
this.$toast.error(this.t('Could not access audio devices.'))
} finally {
this.loading = false
}
},
methods: {
...mapActions(useUserStore, ['saveInputdevice', 'saveOutputDevice']),
normalizeDeviceName (deviceName) {
return deviceName
.replace('Standard - ', '') // Remove 'Standard - '
.replace(/ \(.*\)$/, '') // Remove any content in parentheses
.trim()
},
checkIfSameDevice () {
const input = this.audioInputDevices[this.selectedInput]
const output = this.audioOutputDevices[this.selectedOutput]
if (!input?.label || !output?.label) { return false }
return this.normalizeDeviceName(input.label) === this.normalizeDeviceName(output.label)
},
saveDevices () {
this.saveInputdevice(this.audioInputDevices[this.selectedInput])
this.saveOutputDevice(this.audioOutputDevices[this.selectedOutput])
this.$emit('next-step')
},
async getUserMedia () {
try {
return await navigator.mediaDevices.getUserMedia({ audio: true })
} catch (error) {
this.$logger('keine Mikrofon-Berechtigung erteilt.')
}
}
}
}
</script>
<style scoped>
.bar{
background-color: #e9c046;
}
.select-box{
border: 2px solid #e9c046;
box-shadow: none;
}
.select-box:focus{
border: 2px solid #e9c046;
box-shadow: none;
}
.btn-primary-custom {
background-color: #e9c046;
border-color: #e9c046;
color: white;
font-weight: 700;
}
.btn-primary-custom:hover, .btn-primary-custom:focus{
background-color: transparent;
border-color: #e9c046;
color: #e9c046;
}
</style>