fix(frontend): ファイルタブのセンシティブメディアを開く際に確認ダイアログを出す設定が適用されない問題を修正 (#17019)

* fix(frontend): ファイルタブのセンシティブメディアを開く際に確認ダイアログを出す設定が適用されない問題を修正

* Update Changelog

* refactor

* Update Changelog
This commit is contained in:
かっこかり 2026-01-02 21:41:32 +09:00 committed by GitHub
parent a1ba403f9a
commit 9c22538454
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 73 additions and 40 deletions

View File

@ -15,6 +15,7 @@
- Fix: ドライブクリーナーでファイルを削除しても画面に反映されない問題を修正 #16061
- Fix: 非ログイン時にログインを求めるダイアログが表示された後にダイアログのぼかしが解除されず操作不能になることがある問題を修正
- Fix: ドライブのソートが「登録日(昇順)」の場合に正しく動作しない問題を修正
- Fix: ファイルタブのセンシティブメディアを開く際に確認ダイアログを出す設定が適用されない問題を修正
### Server
- Enhance: OAuthのクライアント情報取得Client Information Discoveryにおいて、IndieWeb Living Standard 11 July 2024で定義されているJSONドキュメント形式に対応しました

View File

@ -100,6 +100,7 @@ import { hms } from '@/filters/hms.js';
import MkMediaRange from '@/components/MkMediaRange.vue';
import { $i, iAmModerator } from '@/i.js';
import { prefer } from '@/preferences.js';
import { canRevealFile, shouldHideFileByDefault } from '@/utility/sensitive-file.js';
const props = defineProps<{
audio: Misskey.entities.DriveFile;
@ -154,16 +155,11 @@ function hasFocus() {
const playerEl = useTemplateRef('playerEl');
const audioEl = useTemplateRef('audioEl');
// eslint-disable-next-line vue/no-setup-props-reactivity-loss
const hide = ref((prefer.s.nsfw === 'force' || prefer.s.dataSaver.media) ? true : (props.audio.isSensitive && prefer.s.nsfw !== 'ignore'));
const hide = ref(shouldHideFileByDefault(props.audio));
async function reveal() {
if (props.audio.isSensitive && prefer.s.confirmWhenRevealingSensitiveMedia) {
const { canceled } = await os.confirm({
type: 'question',
text: i18n.ts.sensitiveMediaRevealConfirm,
});
if (canceled) return;
if (!(await canRevealFile(props.audio))) {
return;
}
hide.value = false;

View File

@ -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="reveal">
<div v-else-if="hide" :class="$style.sensitive" @click="reveal">
<span style="font-size: 1.6em;"><i class="ti ti-alert-triangle"></i></span>
<b>{{ i18n.ts.sensitive }}</b>
<span>{{ i18n.ts.clickToShow }}</span>
@ -27,23 +27,18 @@ SPDX-License-Identifier: AGPL-3.0-only
import { ref } from 'vue';
import * as Misskey from 'misskey-js';
import { i18n } from '@/i18n.js';
import * as os from '@/os.js';
import MkMediaAudio from '@/components/MkMediaAudio.vue';
import { prefer } from '@/preferences.js';
import { shouldHideFileByDefault, canRevealFile } from '@/utility/sensitive-file.js';
const props = defineProps<{
media: Misskey.entities.DriveFile;
}>();
const hide = ref(true);
const hide = ref(shouldHideFileByDefault(props.media));
async function reveal() {
if (props.media.isSensitive && prefer.s.confirmWhenRevealingSensitiveMedia) {
const { canceled } = await os.confirm({
type: 'question',
text: i18n.ts.sensitiveMediaRevealConfirm,
});
if (canceled) return;
if (!(await canRevealFile(props.media))) {
return;
}
hide.value = false;

View File

@ -77,6 +77,7 @@ import { i18n } from '@/i18n.js';
import * as os from '@/os.js';
import { $i, iAmModerator } from '@/i.js';
import { prefer } from '@/preferences.js';
import { shouldHideFileByDefault, canRevealFile } from '@/utility/sensitive-file.js';
const props = withDefaults(defineProps<{
image: Misskey.entities.DriveFile;
@ -106,12 +107,8 @@ async function reveal(ev: MouseEvent) {
if (hide.value) {
ev.stopPropagation();
if (props.image.isSensitive && prefer.s.confirmWhenRevealingSensitiveMedia) {
const { canceled } = await os.confirm({
type: 'question',
text: i18n.ts.sensitiveMediaRevealConfirm,
});
if (canceled) return;
if (!(await canRevealFile(props.image))) {
return;
}
hide.value = false;
@ -119,8 +116,8 @@ async function reveal(ev: MouseEvent) {
}
// Plugin:register_note_view_interruptor 使watch
watch(() => props.image, () => {
hide.value = (prefer.s.nsfw === 'force' || prefer.s.dataSaver.media) ? true : (props.image.isSensitive && prefer.s.nsfw !== 'ignore');
watch(() => props.image, (newImage) => {
hide.value = shouldHideFileByDefault(newImage);
}, {
deep: true,
immediate: true,

View File

@ -124,6 +124,7 @@ import hasAudio from '@/utility/media-has-audio.js';
import MkMediaRange from '@/components/MkMediaRange.vue';
import { $i, iAmModerator } from '@/i.js';
import { prefer } from '@/preferences.js';
import { shouldHideFileByDefault, canRevealFile } from '@/utility/sensitive-file.js';
const props = defineProps<{
video: Misskey.entities.DriveFile;
@ -176,15 +177,11 @@ function hasFocus() {
}
// eslint-disable-next-line vue/no-setup-props-reactivity-loss
const hide = ref((prefer.s.nsfw === 'force' || prefer.s.dataSaver.media) ? true : (props.video.isSensitive && prefer.s.nsfw !== 'ignore'));
const hide = ref(shouldHideFileByDefault(props.video));
async function reveal() {
if (props.video.isSensitive && prefer.s.confirmWhenRevealingSensitiveMedia) {
const { canceled } = await os.confirm({
type: 'question',
text: i18n.ts.sensitiveMediaRevealConfirm,
});
if (canceled) return;
if (!(await canRevealFile(props.video))) {
return;
}
hide.value = false;

View File

@ -6,14 +6,9 @@ SPDX-License-Identifier: AGPL-3.0-only
<template>
<template v-for="file in note.files">
<div
v-if="(((
(prefer.s.nsfw === 'force' || file.isSensitive) &&
prefer.s.nsfw !== 'ignore'
) || (prefer.s.dataSaver.media && file.type.startsWith('image/'))) &&
!showingFiles.has(file.id)
)"
v-if="isHiding(file)"
:class="[$style.filePreview, { [$style.square]: square }]"
@click="showingFiles.add(file.id)"
@click="reveal(file)"
>
<MkDriveFileThumbnail
:file="file"
@ -49,6 +44,7 @@ import * as Misskey from 'misskey-js';
import { notePage } from '@/filters/note.js';
import { i18n } from '@/i18n.js';
import { prefer } from '@/preferences.js';
import { shouldHideFileByDefault, canRevealFile } from '@/utility/sensitive-file.js';
import bytes from '@/filters/bytes.js';
import MkDriveFileThumbnail from '@/components/MkDriveFileThumbnail.vue';
@ -59,6 +55,24 @@ defineProps<{
}>();
const showingFiles = ref<Set<string>>(new Set());
function isHiding(file: Misskey.entities.DriveFile) {
if (shouldHideFileByDefault(file) && !showingFiles.value.has(file.id)) {
if (!file.isSensitive && !file.type.startsWith('image/')) {
return false;
}
return true;
}
return false;
}
async function reveal(file: Misskey.entities.DriveFile) {
if (!(await canRevealFile(file))) {
return;
}
showingFiles.value.add(file.id);
}
</script>
<style lang="scss" module>

View File

@ -0,0 +1,33 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import * as Misskey from 'misskey-js';
import * as os from '@/os.js';
import { prefer } from '@/preferences.js';
import { i18n } from '@/i18n.js';
export function shouldHideFileByDefault(file: Misskey.entities.DriveFile): boolean {
if (prefer.s.nsfw === 'force' || prefer.s.dataSaver.media) {
return true;
}
if (file.isSensitive && prefer.s.nsfw !== 'ignore') {
return true;
}
return false;
}
export async function canRevealFile(file: Misskey.entities.DriveFile): Promise<boolean> {
if (file.isSensitive && prefer.s.confirmWhenRevealingSensitiveMedia) {
const { canceled } = await os.confirm({
type: 'question',
text: i18n.ts.sensitiveMediaRevealConfirm,
});
if (canceled) return false;
}
return true;
}