Skip to content

Commit

Permalink
enhance(frontend): センシティブなメディアを開く際に確認ダイアログを出せるように
Browse files Browse the repository at this point in the history
  • Loading branch information
kakkokari-gtyih committed Jul 2, 2024
1 parent a6edd50 commit 1146ded
Show file tree
Hide file tree
Showing 9 changed files with 74 additions and 17 deletions.
8 changes: 8 additions & 0 deletions locales/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4984,6 +4984,14 @@ export interface Locale extends ILocale {
* お問い合わせ
*/
"inquiry": string;
/**
* センシティブなメディアを表示するとき確認する
*/
"confirmWhenRevealingSensitiveMedia": string;
/**
* センシティブなメディアです。表示しますか?
*/
"sensitiveMediaRevealConfirm": string;
"_delivery": {
/**
* 配信状態
Expand Down
2 changes: 2 additions & 0 deletions locales/ja-JP.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1242,6 +1242,8 @@ keepOriginalFilenameDescription: "この設定をオフにすると、アップ
noDescription: "説明文はありません"
alwaysConfirmFollow: "フォローの際常に確認する"
inquiry: "お問い合わせ"
confirmWhenRevealingSensitiveMedia: "センシティブなメディアを表示するとき確認する"
sensitiveMediaRevealConfirm: "センシティブなメディアです。表示しますか?"

_delivery:
status: "配信状態"
Expand Down
14 changes: 13 additions & 1 deletion packages/frontend/src/components/MkMediaAudio.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -129,6 +129,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);

Expand Down
26 changes: 16 additions & 10 deletions packages/frontend/src/components/MkMediaBanner.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand All @@ -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>
Expand Down
12 changes: 11 additions & 1 deletion packages/frontend/src/components/MkMediaImage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Expand Down
8 changes: 4 additions & 4 deletions packages/frontend/src/components/MkMediaList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -134,15 +134,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);
Expand All @@ -154,6 +152,8 @@ onMounted(() => {
itemData.alt = file.comment ?? file.name;
itemData.comment = file.comment ?? file.name;
itemData.thumbCropped = true;

return itemData;
});

lightbox.on('uiRegister', () => {
Expand Down
14 changes: 13 additions & 1 deletion packages/frontend/src/components/MkMediaVideo.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -163,6 +163,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);

Expand Down
3 changes: 3 additions & 0 deletions packages/frontend/src/pages/settings/general.vue
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkSwitch v-model="disableStreamingTimeline">{{ i18n.ts.disableStreamingTimeline }}</MkSwitch>
<MkSwitch v-model="enableHorizontalSwipe">{{ i18n.ts.enableHorizontalSwipe }}</MkSwitch>
<MkSwitch v-model="alwaysConfirmFollow">{{ i18n.ts.alwaysConfirmFollow }}</MkSwitch>
<MkSwitch v-model="confirmWhenRevealingSensitiveMedia">{{ i18n.ts.confirmWhenRevealingSensitiveMedia }}</MkSwitch>
</div>
<MkSelect v-model="serverDisconnectedBehavior">
<template #label>{{ i18n.ts.whenServerDisconnected }}</template>
Expand Down Expand Up @@ -315,6 +316,7 @@ const enableSeasonalScreenEffect = computed(defaultStore.makeGetterSetter('enabl
const enableHorizontalSwipe = computed(defaultStore.makeGetterSetter('enableHorizontalSwipe'));
const useNativeUIForVideoAudioPlayer = computed(defaultStore.makeGetterSetter('useNativeUIForVideoAudioPlayer'));
const alwaysConfirmFollow = computed(defaultStore.makeGetterSetter('alwaysConfirmFollow'));
const confirmWhenRevealingSensitiveMedia = computed(defaultStore.makeGetterSetter('confirmWhenRevealingSensitiveMedia'));

watch(lang, () => {
miLocalStorage.setItem('lang', lang.value as string);
Expand Down Expand Up @@ -357,6 +359,7 @@ watch([
disableStreamingTimeline,
enableSeasonalScreenEffect,
alwaysConfirmFollow,
confirmWhenRevealingSensitiveMedia,
], async () => {
await reloadAsk();
});
Expand Down
4 changes: 4 additions & 0 deletions packages/frontend/src/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,10 @@ export const defaultStore = markRaw(new Storage('base', {
where: 'device',
default: true,
},
confirmWhenRevealingSensitiveMedia: {
where: 'device',
default: false,
},

sound_masterVolume: {
where: 'device',
Expand Down

0 comments on commit 1146ded

Please sign in to comment.