pleroma-fe/src/components/media_modal/media_modal.js

162 lines
4.5 KiB
JavaScript
Raw Normal View History

import { library } from '@fortawesome/fontawesome-svg-core'
import {
faChevronLeft,
2021-08-16 01:02:56 +03:00
faChevronRight,
2022-03-03 12:51:13 -05:00
faCircleNotch,
2026-01-06 16:22:52 +02:00
faTimes,
} from '@fortawesome/free-solid-svg-icons'
2026-01-06 16:23:17 +02:00
import Flash from 'src/components/flash/flash.vue'
2025-02-03 13:02:14 +02:00
import { useMediaViewerStore } from 'src/stores/media_viewer'
2026-01-06 16:23:17 +02:00
import fileTypeService from '../../services/file_type/file_type.service.js'
import GestureService from '../../services/gesture_service/gesture_service'
import Modal from '../modal/modal.vue'
import PinchZoom from '../pinch_zoom/pinch_zoom.vue'
import StillImage from '../still-image/still-image.vue'
import SwipeClick from '../swipe_click/swipe_click.vue'
import VideoAttachment from '../video_attachment/video_attachment.vue'
2026-01-06 16:22:52 +02:00
library.add(faChevronLeft, faChevronRight, faCircleNotch, faTimes)
const MediaModal = {
components: {
2019-01-26 17:45:03 +02:00
StillImage,
VideoAttachment,
PinchZoom,
SwipeClick,
Modal,
2026-01-06 16:22:52 +02:00
Flash,
},
2026-01-06 16:22:52 +02:00
data() {
2021-08-16 01:02:56 +03:00
return {
loading: false,
swipeDirection: GestureService.DIRECTION_LEFT,
swipeThreshold: () => {
const considerableMoveRatio = 1 / 4
return window.innerWidth * considerableMoveRatio
},
2021-08-02 19:21:18 -04:00
pinchZoomMinScale: 1,
2026-01-06 16:22:52 +02:00
pinchZoomScaleResetLimit: 1.2,
2021-08-16 01:02:56 +03:00
}
},
computed: {
2026-01-06 16:22:52 +02:00
showing() {
2023-04-05 13:55:38 -06:00
return useMediaViewerStore().activated
},
2026-01-06 16:22:52 +02:00
media() {
2023-04-05 13:55:38 -06:00
return useMediaViewerStore().media
},
2026-01-06 16:22:52 +02:00
description() {
2021-08-15 19:45:48 +03:00
return this.currentMedia.description
},
2026-01-06 16:22:52 +02:00
currentIndex() {
2023-04-05 13:55:38 -06:00
return useMediaViewerStore().currentIndex
},
2026-01-06 16:22:52 +02:00
currentMedia() {
return this.media[this.currentIndex]
},
2026-01-06 16:22:52 +02:00
canNavigate() {
return this.media.length > 1
},
2026-01-06 16:22:52 +02:00
type() {
2021-08-16 01:02:56 +03:00
return this.currentMedia ? this.getType(this.currentMedia) : null
},
2026-01-06 16:22:52 +02:00
swipeDisableClickThreshold() {
// If there is only one media, allow more mouse movements to close the modal
// because there is less chance that the user wants to switch to another image
2026-01-06 16:22:52 +02:00
return () => (this.canNavigate ? 1 : 30)
},
},
methods: {
2026-01-06 16:22:52 +02:00
getType(media) {
2021-08-16 01:02:56 +03:00
return fileTypeService.fileType(media.mimetype)
},
2026-01-06 16:22:52 +02:00
hide() {
// HACK: Closing immediately via a touch will cause the click
// to be processed on the content below the overlay
const transitionTime = 100 // ms
setTimeout(() => {
2023-04-05 13:55:38 -06:00
useMediaViewerStore().closeMediaViewer()
}, transitionTime)
},
2026-01-06 16:22:52 +02:00
hideIfNotSwiped(event) {
// If we have swiped over SwipeClick, do not trigger hide
const comp = this.$refs.swipeClick
if (!comp) {
this.hide()
} else {
comp.$gesture.click(event)
}
},
2026-01-06 16:22:52 +02:00
goPrev() {
if (this.canNavigate) {
2026-01-06 16:22:52 +02:00
const prevIndex =
this.currentIndex === 0
? this.media.length - 1
: this.currentIndex - 1
2021-08-16 01:02:56 +03:00
const newMedia = this.media[prevIndex]
if (this.getType(newMedia) === 'image') {
this.loading = true
}
2023-04-05 13:55:38 -06:00
useMediaViewerStore().setCurrentMedia(newMedia)
}
},
2026-01-06 16:22:52 +02:00
goNext() {
if (this.canNavigate) {
2026-01-06 16:22:52 +02:00
const nextIndex =
this.currentIndex === this.media.length - 1
? 0
: this.currentIndex + 1
2021-08-16 01:02:56 +03:00
const newMedia = this.media[nextIndex]
if (this.getType(newMedia) === 'image') {
this.loading = true
}
2023-04-05 13:55:38 -06:00
useMediaViewerStore().setCurrentMedia(newMedia)
}
},
2026-01-06 16:22:52 +02:00
onImageLoaded() {
2021-08-16 01:02:56 +03:00
this.loading = false
},
2026-01-06 16:22:52 +02:00
handleSwipePreview(offsets) {
this.$refs.pinchZoom.setTransform({ scale: 1, x: offsets[0], y: 0 })
2021-08-01 19:46:27 -04:00
},
2026-01-06 16:22:52 +02:00
handleSwipeEnd(sign) {
this.$refs.pinchZoom.setTransform({ scale: 1, x: 0, y: 0 })
if (sign > 0) {
2021-08-01 19:46:27 -04:00
this.goNext()
} else if (sign < 0) {
2021-08-01 19:46:27 -04:00
this.goPrev()
}
},
2026-01-06 16:22:52 +02:00
handleKeyupEvent(e) {
if (this.showing && e.keyCode === 27) {
// escape
this.hide()
}
},
2026-01-06 16:22:52 +02:00
handleKeydownEvent(e) {
if (!this.showing) {
return
}
2026-01-06 16:22:52 +02:00
if (e.keyCode === 39) {
// arrow right
this.goNext()
2026-01-06 16:22:52 +02:00
} else if (e.keyCode === 37) {
// arrow left
this.goPrev()
}
2026-01-06 16:22:52 +02:00
},
},
2026-01-06 16:22:52 +02:00
mounted() {
window.addEventListener('popstate', this.hide)
document.addEventListener('keyup', this.handleKeyupEvent)
document.addEventListener('keydown', this.handleKeydownEvent)
},
2026-01-06 16:22:52 +02:00
unmounted() {
window.removeEventListener('popstate', this.hide)
document.removeEventListener('keyup', this.handleKeyupEvent)
document.removeEventListener('keydown', this.handleKeydownEvent)
2026-01-06 16:22:52 +02:00
},
}
export default MediaModal