diff --git a/config/webpack/webpack.common.js b/config/webpack/webpack.common.js index ff726fdbc1..c3093cb519 100644 --- a/config/webpack/webpack.common.js +++ b/config/webpack/webpack.common.js @@ -173,6 +173,7 @@ module.exports = { "@feature-folder": getDir("src/modules/feature/folder"), "@icons": getDir("src/components/icons"), "@ui-alert": getDir("src/modules/ui/alert"), + "@ui-audio-player": getDir("src/modules/ui/audio-player"), "@ui-board": getDir("src/modules/ui/board"), "@ui-breadcrumbs": getDir("src/modules/ui/breadcrumbs"), "@ui-chip": getDir("src/modules/ui/chip"), diff --git a/src/locales/de.ts b/src/locales/de.ts index 8f6ab5d6b1..e909dc5ccf 100644 --- a/src/locales/de.ts +++ b/src/locales/de.ts @@ -211,12 +211,6 @@ export default { "common.words.topic": "Thema", "common.words.topics": "Themen", "common.words.yes": "Ja", - "component.cardElement.fileElement.audioPlayer.pause": "Anhalten", - "component.cardElement.fileElement.audioPlayer.play": "Abspielen", - "component.cardElement.fileElement.audioPlayer.slider": - "Audio Schieberegler für Fortschritt", - "component.cardElement.fileElement.audioPlayer.speed.normal": "Normal", - "component.cardElement.fileElement.audioPlayer.speed": "Geschwindigkeitsmenü", "components.administration.adminMigrationSection.description.firstPart": "Bei der Migration wird das Anmeldesystem der Schüler:innen und Lehrkräfte zu moin.schule gewechselt. Die zu den betroffenen Accounts gehörenden Daten bleiben erhalten.", "components.administration.adminMigrationSection.description.secondPart": @@ -428,6 +422,11 @@ export default { "components.atoms.VCustomChipTimeRemaining.hintHoursShort": "h", "components.atoms.VCustomChipTimeRemaining.hintMinShort": "min", "components.atoms.VCustomChipTimeRemaining.hintMinutes": "Minute | Minuten", + "components.audioPlayer.pause": "Anhalten", + "components.audioPlayer.play": "Abspielen", + "components.audioPlayer.slider": "Audio Schieberegler für Fortschritt", + "components.audioPlayer.speed": "Geschwindigkeitsmenü", + "components.audioPlayer.speed.normal": "Normal", "components.base.BaseIcon.error": "Das Icon aus dieser Quelle konnte leider nicht geladen werden. Falls Sie Microsoft Edge verwenden, stellen Sie bitte sicher, dass Sie die neuste Version verwenden.", "components.base.showPassword": "Passwort anzeigen", diff --git a/src/locales/en.ts b/src/locales/en.ts index 2a0963eb58..e51b93692d 100644 --- a/src/locales/en.ts +++ b/src/locales/en.ts @@ -211,11 +211,6 @@ export default { "common.words.topics": "Topics", "common.words.yes": "Yes", "common.words.export": "Course export is downloading", - "component.cardElement.fileElement.audioPlayer.pause": "Pause", - "component.cardElement.fileElement.audioPlayer.play": "Play", - "component.cardElement.fileElement.audioPlayer.slider": "Audio slider", - "component.cardElement.fileElement.audioPlayer.speed.normal": "Normal", - "component.cardElement.fileElement.audioPlayer.speed": "Speed Menu", "components.administration.adminMigrationSection.description.firstPart": "During the migration, the registration system for students and teachers is changed to moin.schule. The data belonging to the affected accounts will be preserved.", "components.administration.adminMigrationSection.description.secondPart": @@ -426,6 +421,11 @@ export default { "components.atoms.VCustomChipTimeRemaining.hintHoursShort": "h", "components.atoms.VCustomChipTimeRemaining.hintMinShort": "min", "components.atoms.VCustomChipTimeRemaining.hintMinutes": "minute | minutes", + "components.audioPlayer.pause": "Pause", + "components.audioPlayer.play": "Play", + "components.audioPlayer.slider": "Audio slider", + "components.audioPlayer.speed": "Speed Menu", + "components.audioPlayer.speed.normal": "Normal", "components.base.BaseIcon.error": "error loading icon {icon} from {source}. It might be not available or you are using the legacy Edge browser.", "components.base.showPassword": "Show password", diff --git a/src/locales/es.ts b/src/locales/es.ts index c0a543b8bf..e4dd36e512 100644 --- a/src/locales/es.ts +++ b/src/locales/es.ts @@ -213,11 +213,6 @@ export default { "common.words.topics": "Temas", "common.words.yes": "Sí", "common.words.export": "La exportación del curso se está descargando", - "component.cardElement.fileElement.audioPlayer.pause": "Pausa", - "component.cardElement.fileElement.audioPlayer.play": "Reproducir", - "component.cardElement.fileElement.audioPlayer.slider": "Control deslizante", - "component.cardElement.fileElement.audioPlayer.speed.normal": "Normal", - "component.cardElement.fileElement.audioPlayer.speed": "Menú de velocidad", "components.administration.adminMigrationSection.description.firstPart": "Durante la migración se cambia el sistema de registro de alumnos y profesores a moin.schule. Los datos pertenecientes a las cuentas afectadas se conservarán.", "components.administration.adminMigrationSection.description.secondPart": @@ -432,6 +427,11 @@ export default { "components.atoms.VCustomChipTimeRemaining.hintHoursShort": "h", "components.atoms.VCustomChipTimeRemaining.hintMinShort": "min", "components.atoms.VCustomChipTimeRemaining.hintMinutes": "minuto | minutos", + "components.audioPlayer.pause": "Pausa", + "components.audioPlayer.play": "Reproducir", + "components.audioPlayer.slider": "Control deslizante", + "components.audioPlayer.speed": "Menú de velocidad", + "components.audioPlayer.speed.normal": "Normal", "components.base.BaseIcon.error": "Error al cargar el icono {icon} de {source}. Es posible que no esté disponible o que estés utilizando el navegador Edge heredado.", "components.base.showPassword": "Mostrar contraseña", diff --git a/src/locales/uk.ts b/src/locales/uk.ts index 1860e86bb9..ba137d9bad 100644 --- a/src/locales/uk.ts +++ b/src/locales/uk.ts @@ -215,11 +215,6 @@ export default { "common.words.topics": "теми", "common.words.yes": "Так", "common.words.export": "Завантажується експорт курсу", - "component.cardElement.fileElement.audioPlayer.pause": "пауза", - "component.cardElement.fileElement.audioPlayer.play": "грати", - "component.cardElement.fileElement.audioPlayer.slider": "повзунок", - "component.cardElement.fileElement.audioPlayer.speed.normal": "нормальний", - "component.cardElement.fileElement.audioPlayer.speed": "швидке меню", "components.administration.adminMigrationSection.description.firstPart": "Під час міграції система реєстрації студентів і викладачів змінена на moin.schule. Дані відповідних облікових записів буде збережено.", "components.administration.adminMigrationSection.description.secondPart": @@ -436,6 +431,11 @@ export default { "components.atoms.VCustomChipTimeRemaining.hintMinShort": "хв", "components.atoms.VCustomChipTimeRemaining.hintMinutes": "хвилина | хвилини (хвилин)", + "components.audioPlayer.pause": "пауза", + "components.audioPlayer.play": "грати", + "components.audioPlayer.slider": "повзунок", + "components.audioPlayer.speed": "швидке меню", + "components.audioPlayer.speed.normal": "нормальний", "components.base.BaseIcon.error": "помилка завантаження значка {icon} з {source}. Можливо, він недоступний або ви використовуєте застарілий браузер Edge.", "components.base.showPassword": "Показати пароль", diff --git a/src/modules/feature/board-file-element/content/display/audio-display/AudioDisplay.unit.ts b/src/modules/feature/board-file-element/content/display/audio-display/AudioDisplay.unit.ts index 4ee21c0a7c..c0ded5c9c4 100644 --- a/src/modules/feature/board-file-element/content/display/audio-display/AudioDisplay.unit.ts +++ b/src/modules/feature/board-file-element/content/display/audio-display/AudioDisplay.unit.ts @@ -1,257 +1,62 @@ -import { - createTestingI18n, - createTestingVuetify, -} from "@@/tests/test-utils/setup"; -import { createMock } from "@golevelup/ts-jest"; -import { mdiPause, mdiPlay } from "@icons/material"; +import { createTestingI18n } from "@@/tests/test-utils/setup"; import { mount } from "@vue/test-utils"; -import { useMediaControls } from "@vueuse/core"; -import { nextTick, ref } from "vue"; import AudioDisplay from "./AudioDisplay.vue"; -jest.mock("@vueuse/core", () => { - const original = jest.requireActual("@vueuse/core"); - - return { - ...original, - useMediaControls: jest.fn(), - }; -}); - describe("AudioDisplay", () => { - describe("when audio is not playing", () => { - const setup = (options?: { showMenu?: boolean }) => { - const src = "test-source"; - const slotContent = "test-slot-content"; - const props = { - src, - showMenu: options?.showMenu ?? true, - }; - - const currentTimeRef = ref(0); - const durationRef = ref(50); - const rateRef = ref(1); - const playingRef = ref(false); - const onSourceErrorMock = jest.fn(); - - const useMediaControlsMock = createMock< - ReturnType - >({ - playing: playingRef, - currentTime: currentTimeRef, - duration: durationRef, - rate: rateRef, - onSourceError: onSourceErrorMock, - }); - jest.mocked(useMediaControls).mockReturnValue(useMediaControlsMock); - - const wrapper = mount(AudioDisplay, { - props, - slots: { - default: slotContent, - }, - global: { plugins: [createTestingVuetify(), createTestingI18n()] }, - }); - - const contentElementBar = wrapper.findComponent({ - name: "ContentElementBar", - }); - - return { - wrapper, - src, - currentTimeRef, - durationRef, - playingRef, - rateRef, - contentElementBar, - onSourceErrorMock, - }; + const setup = (options?: { showMenu?: boolean }) => { + const src = "test-source"; + const slotContent = "test-slot-content"; + const props = { + src, + showMenu: options?.showMenu ?? true, }; - it("should render slot content if showMenu is true", () => { - const { wrapper } = setup({ showMenu: true }); - - expect(wrapper.text()).toContain("test-slot-content"); - }); - - it("should render slot content if showMenu is false", () => { - const { wrapper } = setup({ showMenu: false }); - - expect(wrapper.text()).not.toContain("test-slot-content"); + const wrapper = mount(AudioDisplay, { + props, + slots: { + default: slotContent, + }, + global: { plugins: [createTestingI18n()] }, }); - it("should call onSourceError", () => { - const { onSourceErrorMock } = setup(); - - expect(onSourceErrorMock).toHaveBeenCalled(); - }); - - it("should render audio element with lazy prop", () => { - const { wrapper } = setup(); - - const audio = wrapper.find("audio"); - - expect(audio.attributes("loading")).toBe("lazy"); - }); - - it("should pass duration to v-slider", () => { - const { wrapper, durationRef } = setup(); - - const slider = wrapper.findComponent({ name: "v-slider" }); - - expect(slider.props("max")).toBe(durationRef.value); - }); - - it("should pass currentTime to v-slider", () => { - const { wrapper, currentTimeRef } = setup(); - - const slider = wrapper.findComponent({ name: "v-slider" }); - - expect(slider.props("modelValue")).toBe(currentTimeRef.value); - }); - - it("should have an accessible play button", () => { - const { wrapper } = setup(); - - const playButton = wrapper.findComponent({ name: "v-btn" }); - const playIcon = wrapper.findComponent({ name: "v-icon" }); - - expect(playButton.attributes("aria-label")).toBe( - "component.cardElement.fileElement.audioPlayer.play" - ); - expect(playIcon.html()).toContain(mdiPlay); - }); - - it("should display duration", () => { - const { wrapper } = setup(); - - const duration = wrapper.find(".duration"); - expect(duration.text()).toBe("00:00 / 00:50"); + const contentElementBar = wrapper.findComponent({ + name: "ContentElementBar", }); - describe("when play button is clicked", () => { - it("playing should be set to true", async () => { - const { wrapper, playingRef } = setup(); - - const playButton = wrapper.findComponent({ name: "v-btn" }); - - playButton.trigger("click"); - - await nextTick(); - - expect(playingRef.value).toBe(true); - }); - }); - - describe("when duration slider emits input", () => { - it("should set current time", async () => { - const { wrapper, currentTimeRef } = setup(); - - const audioSlider = wrapper.findComponent({ name: "v-slider" }); - - audioSlider.setValue(10); - - await nextTick(); - - expect(currentTimeRef.value).toBe(10); - }); - }); - - it("should render speed menu component with correct props", async () => { - const { wrapper, rateRef } = setup(); - - const speedMenu = wrapper.findComponent({ name: "SpeedMenu" }); - expect(speedMenu.props("rate")).toBe(rateRef.value); - }); - - describe("when speed menu emits speedChange", () => { - it("should set rate to new value", async () => { - const { wrapper, rateRef } = setup(); - - const newRateValue = 2; - const speedMenu = wrapper.findComponent({ name: "SpeedMenu" }); - speedMenu.vm.$emit("updateRate", newRateValue); - - await nextTick(); - - expect(rateRef.value).toBe(newRateValue); - }); - }); - }); - - describe("when audio is playing", () => { - const setup = () => { - const src = "test-source"; - const slotContent = "test-slot-content"; - const props = { - src, - showMenu: true, - }; - - const currentTimeRef = ref(5); - const durationRef = ref(50); - const rateRef = ref(1); - const playingRef = ref(true); - - const useMediaControlsMock = createMock< - ReturnType - >({ - playing: playingRef, - currentTime: currentTimeRef, - duration: durationRef, - rate: rateRef, - }); - jest.mocked(useMediaControls).mockReturnValue(useMediaControlsMock); - - const wrapper = mount(AudioDisplay, { - props, - slots: { - default: slotContent, - }, - global: { plugins: [createTestingVuetify(), createTestingI18n()] }, - }); - - return { - wrapper, - src, - currentTimeRef, - durationRef, - playingRef, - rateRef, - }; + return { + wrapper, + src, + contentElementBar, }; + }; - it("should display duration", () => { - const { wrapper } = setup(); + it("should render AudioPlayer with correct src", () => { + const { wrapper, src } = setup(); - const duration = wrapper.find(".duration"); - expect(duration.text()).toBe("00:05 / 00:50"); - }); + const audioPlayer = wrapper.findComponent({ name: "AudioPlayer" }); + expect(audioPlayer.exists()).toBe(true); + expect(audioPlayer.props("src")).toBe(src); + }); - it("should have an accessible pause button", () => { - const { wrapper } = setup(); + it("should emit error from AudioPlayer", () => { + const { wrapper } = setup(); + const audioPlayer = wrapper.findComponent({ name: "AudioPlayer" }); + const error = new Error("Test error"); - const playButton = wrapper.findComponent({ name: "v-btn" }); - const playIcon = wrapper.findComponent({ name: "v-icon" }); + audioPlayer.vm.$emit("error", error); - expect(playButton.attributes("aria-label")).toBe( - "component.cardElement.fileElement.audioPlayer.pause" - ); - expect(playIcon.html()).toContain(mdiPause); - }); + expect(wrapper.emitted("error")).toBeTruthy(); + }); - describe("when play button is clicked", () => { - it("playing should be set to false", async () => { - const { wrapper, playingRef } = setup(); + it("should render slot content if showMenu is true", () => { + const { wrapper } = setup({ showMenu: true }); - const playButton = wrapper.findComponent({ name: "v-btn" }); - playButton.trigger("click"); + expect(wrapper.text()).toContain("test-slot-content"); + }); - await nextTick(); + it("should render slot content if showMenu is false", () => { + const { wrapper } = setup({ showMenu: false }); - expect(playingRef.value).toBe(false); - }); - }); + expect(wrapper.text()).not.toContain("test-slot-content"); }); }); diff --git a/src/modules/feature/board-file-element/content/display/audio-display/AudioDisplay.vue b/src/modules/feature/board-file-element/content/display/audio-display/AudioDisplay.vue index 115da21f3a..dd8876cfd7 100644 --- a/src/modules/feature/board-file-element/content/display/audio-display/AudioDisplay.vue +++ b/src/modules/feature/board-file-element/content/display/audio-display/AudioDisplay.vue @@ -1,141 +1,38 @@ - diff --git a/src/modules/feature/board-file-element/content/display/image-display/ImageDisplay.unit.ts b/src/modules/feature/board-file-element/content/display/image-display/ImageDisplay.unit.ts index 33bcd51182..37f7d3037e 100644 --- a/src/modules/feature/board-file-element/content/display/image-display/ImageDisplay.unit.ts +++ b/src/modules/feature/board-file-element/content/display/image-display/ImageDisplay.unit.ts @@ -4,7 +4,11 @@ import { createTestingI18n, createTestingVuetify, } from "@@/tests/test-utils/setup"; -import { LightBoxOptions, useLightBox } from "@ui-light-box"; +import { + LightBoxContentType, + LightBoxOptions, + useLightBox, +} from "@ui-light-box"; import { mount } from "@vue/test-utils"; import { ref } from "vue"; import ImageDisplay from "./ImageDisplay.vue"; @@ -31,9 +35,13 @@ describe("ImageDisplay", () => { showMenu: true, }; - const isLightBoxOpen = ref(false); const open = jest.fn(); - mockedUseLightBox.mockReturnValue({ isLightBoxOpen, open }); + mockedUseLightBox.mockReturnValue({ + isLightBoxOpen: ref(false), + open, + close: jest.fn(), + lightBoxOptions: ref(), + }); mockedConvertDownloadToPreviewUrl.mockImplementation( (downloadUrl) => downloadUrl @@ -115,6 +123,7 @@ describe("ImageDisplay", () => { alternativeText, }); const options: LightBoxOptions = { + type: LightBoxContentType.IMAGE, downloadUrl: src, previewUrl: src, alt: alternativeText, @@ -140,6 +149,7 @@ describe("ImageDisplay", () => { alternativeText, }); const options: LightBoxOptions = { + type: LightBoxContentType.IMAGE, downloadUrl: src, previewUrl: src, alt: alternativeText, diff --git a/src/modules/feature/board-file-element/content/display/image-display/ImageDisplay.vue b/src/modules/feature/board-file-element/content/display/image-display/ImageDisplay.vue index f9c60470fc..a3ec5fbfc2 100644 --- a/src/modules/feature/board-file-element/content/display/image-display/ImageDisplay.vue +++ b/src/modules/feature/board-file-element/content/display/image-display/ImageDisplay.vue @@ -31,7 +31,11 @@ import { FileElementResponse } from "@/serverApi/v3"; import { convertDownloadToPreviewUrl } from "@/utils/fileHelper"; import { ContentElementBar } from "@ui-board"; -import { LightBoxOptions, useLightBox } from "@ui-light-box"; +import { + LightBoxOptions, + LightBoxContentType, + useLightBox, +} from "@ui-light-box"; import { PreviewImage } from "@ui-preview-image"; import { PropType, computed, defineComponent, ref } from "vue"; import { useI18n } from "vue-i18n"; @@ -67,6 +71,7 @@ export default defineComponent({ const previewUrl = convertDownloadToPreviewUrl(props.src); const options: LightBoxOptions = { + type: LightBoxContentType.IMAGE, downloadUrl: props.src, previewUrl: previewUrl, alt: alternativeText.value, diff --git a/src/modules/feature/folder/file-table/FileInteractionHandler.unit.ts b/src/modules/feature/folder/file-table/FileInteractionHandler.unit.ts index 7c6202bf1a..33070fcb69 100644 --- a/src/modules/feature/folder/file-table/FileInteractionHandler.unit.ts +++ b/src/modules/feature/folder/file-table/FileInteractionHandler.unit.ts @@ -11,9 +11,12 @@ jest.mock("@ui-light-box"); describe("FileInteractionHandler", () => { const setupMocks = () => { const useLightBoxMock = jest.mocked(useLightBox); - const isLightBoxOpen = ref(false); - const open = jest.fn(); - useLightBoxMock.mockReturnValue({ isLightBoxOpen, open }); + useLightBoxMock.mockReturnValue({ + isLightBoxOpen: ref(false), + open: jest.fn(), + close: jest.fn(), + lightBoxOptions: ref(), + }); return { useLightBoxMock }; }; @@ -30,10 +33,14 @@ describe("FileInteractionHandler", () => { return { wrapper }; }; - describe("when file is selectable and preview is possible", () => { - const setup = () => { + describe("when file is selectable", () => { + const setup = (props: { + previewStatus?: FilePreviewStatus; + mimeType?: string; + }) => { const fileRecord = fileRecordFactory.build({ - previewStatus: FilePreviewStatus.PREVIEW_POSSIBLE, + previewStatus: props.previewStatus, + mimeType: props.mimeType, }); const fileRecordItem = { ...fileRecord, @@ -45,59 +52,72 @@ describe("FileInteractionHandler", () => { return { wrapper, useLightBoxMock }; }; + describe("when preview is possible", () => { + it("should render button", () => { + const { wrapper } = setup({ + previewStatus: FilePreviewStatus.PREVIEW_POSSIBLE, + }); - it("should render button", () => { - const { wrapper } = setup(); - - const button = wrapper.find("button"); + const button = wrapper.find("button"); - expect(button.exists()).toBe(true); - }); + expect(button.exists()).toBe(true); + }); - it("should open lightbox when button is clicked", () => { - const { wrapper, useLightBoxMock } = setup(); + it("should open lightbox when button is clicked", () => { + const { wrapper, useLightBoxMock } = setup({ + previewStatus: FilePreviewStatus.PREVIEW_POSSIBLE, + }); - const button = wrapper.find("button"); - button.trigger("click"); + const button = wrapper.find("button"); + button.trigger("click"); - expect(useLightBoxMock().open).toHaveBeenCalled(); + expect(useLightBoxMock().open).toHaveBeenCalled(); + }); }); - }); - describe("when file is not selectable", () => { - const setup = () => { - const fileRecord = fileRecordFactory.build({ - previewStatus: FilePreviewStatus.PREVIEW_POSSIBLE, + describe("when file is an audio", () => { + it("should render button", () => { + const { wrapper } = setup({ mimeType: "audio/..." }); + + const button = wrapper.find("button"); + + expect(button.exists()).toBe(true); }); - const fileRecordItem = { - ...fileRecord, - isSelectable: false, - }; - const { wrapper } = setupWrapper(fileRecordItem); + it("should open lightbox when button is clicked", () => { + const { wrapper, useLightBoxMock } = setup({ mimeType: "audio/..." }); - return { wrapper }; - }; + const button = wrapper.find("button"); + button.trigger("click"); - it("should render div instead of button", () => { - const { wrapper } = setup(); + expect(useLightBoxMock().open).toHaveBeenCalled(); + }); + }); - const div = wrapper.find("div"); - const button = wrapper.find("button"); + describe("when preview is not possible and mimeType is not audio", () => { + it("should render div instead of button", () => { + const { wrapper } = setup({ + previewStatus: FilePreviewStatus.PREVIEW_NOT_POSSIBLE_WRONG_MIME_TYPE, + mimeType: "some-mime-type", + }); - expect(div.exists()).toBe(true); - expect(button.exists()).toBe(false); + const div = wrapper.find("div"); + const button = wrapper.find("button"); + + expect(div.exists()).toBe(true); + expect(button.exists()).toBe(false); + }); }); }); - describe("when preview is not possible", () => { + describe("when file is not selectable", () => { const setup = () => { const fileRecord = fileRecordFactory.build({ - previewStatus: FilePreviewStatus.PREVIEW_NOT_POSSIBLE_WRONG_MIME_TYPE, + previewStatus: FilePreviewStatus.PREVIEW_POSSIBLE, }); const fileRecordItem = { ...fileRecord, - isSelectable: true, + isSelectable: false, }; const { wrapper } = setupWrapper(fileRecordItem); diff --git a/src/modules/feature/folder/file-table/FileInteractionHandler.vue b/src/modules/feature/folder/file-table/FileInteractionHandler.vue index 530766e977..c71bee3729 100644 --- a/src/modules/feature/folder/file-table/FileInteractionHandler.vue +++ b/src/modules/feature/folder/file-table/FileInteractionHandler.vue @@ -3,7 +3,7 @@ v-if="isInteractive" :aria-label="t('common.ariaLabel.openImageInLightBox')" class="interactive-area" - @click="openImageInLightbox" + @click="handleClick" > @@ -15,9 +15,10 @@ diff --git a/src/modules/feature/board-file-element/content/display/audio-display/SpeedMenu.unit.ts b/src/modules/ui/audio-player/SpeedMenu.unit.ts similarity index 100% rename from src/modules/feature/board-file-element/content/display/audio-display/SpeedMenu.unit.ts rename to src/modules/ui/audio-player/SpeedMenu.unit.ts diff --git a/src/modules/feature/board-file-element/content/display/audio-display/SpeedMenu.vue b/src/modules/ui/audio-player/SpeedMenu.vue similarity index 94% rename from src/modules/feature/board-file-element/content/display/audio-display/SpeedMenu.vue rename to src/modules/ui/audio-player/SpeedMenu.vue index 1cd39da30e..636a9474d4 100644 --- a/src/modules/feature/board-file-element/content/display/audio-display/SpeedMenu.vue +++ b/src/modules/ui/audio-player/SpeedMenu.vue @@ -8,7 +8,7 @@ density="comfortable" icon variant="flat" - :aria-label="$t('component.cardElement.fileElement.audioPlayer.speed')" + :aria-label="$t('components.audioPlayer.speed')" > {{ mdiPlaySpeed }} @@ -42,7 +42,7 @@
{{ - $t("component.cardElement.fileElement.audioPlayer.speed.normal") + $t("components.audioPlayer.speed.normal") }}