enhance(frontend): センシティブなメディアを開く際に確認ダイアログを出せるように (#14115)
* enhance(frontend): センシティブなメディアを開く際に確認ダイアログを出せるように * Update Changelog
This commit is contained in:
		| @@ -15,7 +15,7 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
| 	@contextmenu.stop | ||||
| 	@keydown.stop | ||||
| > | ||||
| 	<button v-if="hide" :class="$style.hidden" @click="hide = false"> | ||||
| 	<button v-if="hide" :class="$style.hidden" @click="show"> | ||||
| 		<div :class="$style.hiddenTextWrapper"> | ||||
| 			<b v-if="audio.isSensitive" style="display: block;"><i class="ti ti-eye-exclamation"></i> {{ i18n.ts.sensitive }}{{ defaultStore.state.dataSaver.media ? ` (${i18n.ts.audio}${audio.size ? ' ' + bytes(audio.size) : ''})` : '' }}</b> | ||||
| 			<b v-else style="display: block;"><i class="ti ti-music"></i> {{ defaultStore.state.dataSaver.media && audio.size ? bytes(audio.size) : i18n.ts.audio }}</b> | ||||
| @@ -156,6 +156,18 @@ const audioEl = shallowRef<HTMLAudioElement>(); | ||||
| // eslint-disable-next-line vue/no-setup-props-reactivity-loss | ||||
| const hide = ref((defaultStore.state.nsfw === 'force' || defaultStore.state.dataSaver.media) ? true : (props.audio.isSensitive && defaultStore.state.nsfw !== 'ignore')); | ||||
|  | ||||
| async function show() { | ||||
| 	if (props.audio.isSensitive && defaultStore.state.confirmWhenRevealingSensitiveMedia) { | ||||
| 		const { canceled } = await os.confirm({ | ||||
| 			type: 'question', | ||||
| 			text: i18n.ts.sensitiveMediaRevealConfirm, | ||||
| 		}); | ||||
| 		if (canceled) return; | ||||
| 	} | ||||
|  | ||||
| 	hide.value = false; | ||||
| } | ||||
|  | ||||
| // Menu | ||||
| const menuShowing = ref(false); | ||||
|  | ||||
|   | ||||
| @@ -6,7 +6,7 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
| <template> | ||||
| <div :class="$style.root"> | ||||
| 	<MkMediaAudio v-if="media.type.startsWith('audio') && media.type !== 'audio/midi'" :audio="media"/> | ||||
| 	<div v-else-if="media.isSensitive && hide" :class="$style.sensitive" @click="hide = false"> | ||||
| 	<div v-else-if="media.isSensitive && hide" :class="$style.sensitive" @click="show"> | ||||
| 		<span style="font-size: 1.6em;"><i class="ti ti-alert-triangle"></i></span> | ||||
| 		<b>{{ i18n.ts.sensitive }}</b> | ||||
| 		<span>{{ i18n.ts.clickToShow }}</span> | ||||
| @@ -24,24 +24,30 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
| </template> | ||||
|  | ||||
| <script lang="ts" setup> | ||||
| import { shallowRef, watch, ref } from 'vue'; | ||||
| import { ref } from 'vue'; | ||||
| import * as Misskey from 'misskey-js'; | ||||
| import { i18n } from '@/i18n.js'; | ||||
| import { defaultStore } from '@/store.js'; | ||||
| import * as os from '@/os.js'; | ||||
| import MkMediaAudio from '@/components/MkMediaAudio.vue'; | ||||
|  | ||||
| const props = withDefaults(defineProps<{ | ||||
| const props = defineProps<{ | ||||
| 	media: Misskey.entities.DriveFile; | ||||
| }>(), { | ||||
| }); | ||||
| }>(); | ||||
|  | ||||
| const audioEl = shallowRef<HTMLAudioElement>(); | ||||
| const hide = ref(true); | ||||
|  | ||||
| watch(audioEl, () => { | ||||
| 	if (audioEl.value) { | ||||
| 		audioEl.value.volume = 0.3; | ||||
| async function show() { | ||||
| 	if (props.media.isSensitive && defaultStore.state.confirmWhenRevealingSensitiveMedia) { | ||||
| 		const { canceled } = await os.confirm({ | ||||
| 			type: 'question', | ||||
| 			text: i18n.ts.sensitiveMediaRevealConfirm, | ||||
| 		}); | ||||
| 		if (canceled) return; | ||||
| 	} | ||||
| }); | ||||
|  | ||||
| 	hide.value = false; | ||||
| } | ||||
| </script> | ||||
|  | ||||
| <style lang="scss" module> | ||||
|   | ||||
| @@ -83,11 +83,21 @@ const url = computed(() => (props.raw || defaultStore.state.loadRawImages) | ||||
| 		: props.image.thumbnailUrl, | ||||
| ); | ||||
|  | ||||
| function onclick() { | ||||
| async function onclick(ev: MouseEvent) { | ||||
| 	if (!props.controls) { | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	if (hide.value) { | ||||
| 		ev.stopPropagation(); | ||||
| 		if (props.image.isSensitive && defaultStore.state.confirmWhenRevealingSensitiveMedia) { | ||||
| 			const { canceled } = await os.confirm({ | ||||
| 				type: 'question', | ||||
| 				text: i18n.ts.sensitiveMediaRevealConfirm, | ||||
| 			}); | ||||
| 			if (canceled) return; | ||||
| 		} | ||||
|  | ||||
| 		hide.value = false; | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -138,15 +138,13 @@ onMounted(() => { | ||||
| 		pswpModule: PhotoSwipe, | ||||
| 	}); | ||||
|  | ||||
| 	lightbox.on('itemData', (ev) => { | ||||
| 		const { itemData } = ev; | ||||
|  | ||||
| 	lightbox.addFilter('itemData', (itemData) => { | ||||
| 		// element is children | ||||
| 		const { element } = itemData; | ||||
|  | ||||
| 		const id = element?.dataset.id; | ||||
| 		const file = props.mediaList.find(media => media.id === id); | ||||
| 		if (!file) return; | ||||
| 		if (!file) return itemData; | ||||
|  | ||||
| 		itemData.src = file.url; | ||||
| 		itemData.w = Number(file.properties.width); | ||||
| @@ -158,6 +156,8 @@ onMounted(() => { | ||||
| 		itemData.alt = file.comment ?? file.name; | ||||
| 		itemData.comment = file.comment ?? file.name; | ||||
| 		itemData.thumbCropped = true; | ||||
|  | ||||
| 		return itemData; | ||||
| 	}); | ||||
|  | ||||
| 	lightbox.on('uiRegister', () => { | ||||
|   | ||||
| @@ -18,7 +18,7 @@ SPDX-License-Identifier: AGPL-3.0-only | ||||
| 	@contextmenu.stop | ||||
| 	@keydown.stop | ||||
| > | ||||
| 	<button v-if="hide" :class="$style.hidden" @click="hide = false"> | ||||
| 	<button v-if="hide" :class="$style.hidden" @click="show"> | ||||
| 		<div :class="$style.hiddenTextWrapper"> | ||||
| 			<b v-if="video.isSensitive" style="display: block;"><i class="ti ti-eye-exclamation"></i> {{ i18n.ts.sensitive }}{{ defaultStore.state.dataSaver.media ? ` (${i18n.ts.video}${video.size ? ' ' + bytes(video.size) : ''})` : '' }}</b> | ||||
| 			<b v-else style="display: block;"><i class="ti ti-movie"></i> {{ defaultStore.state.dataSaver.media && video.size ? bytes(video.size) : i18n.ts.video }}</b> | ||||
| @@ -176,6 +176,18 @@ function hasFocus() { | ||||
| // eslint-disable-next-line vue/no-setup-props-reactivity-loss | ||||
| const hide = ref((defaultStore.state.nsfw === 'force' || defaultStore.state.dataSaver.media) ? true : (props.video.isSensitive && defaultStore.state.nsfw !== 'ignore')); | ||||
|  | ||||
| async function show() { | ||||
| 	if (props.video.isSensitive && defaultStore.state.confirmWhenRevealingSensitiveMedia) { | ||||
| 		const { canceled } = await os.confirm({ | ||||
| 			type: 'question', | ||||
| 			text: i18n.ts.sensitiveMediaRevealConfirm, | ||||
| 		}); | ||||
| 		if (canceled) return; | ||||
| 	} | ||||
|  | ||||
| 	hide.value = false; | ||||
| } | ||||
|  | ||||
| // Menu | ||||
| const menuShowing = ref(false); | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 かっこかり
					かっこかり