Skip to content

Commit

Permalink
Merge pull request #392 from qwreey75/develop
Browse files Browse the repository at this point in the history
feat: double click to open NSFW media
  • Loading branch information
noridev authored Nov 3, 2023
2 parents 073d968 + afc13d9 commit 1dc0f88
Show file tree
Hide file tree
Showing 9 changed files with 73 additions and 7 deletions.
4 changes: 4 additions & 0 deletions locales/en-US.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1247,6 +1247,7 @@ additionalPermissionsForFlash: "Allow to add permission to Play"
thisFlashRequiresTheFollowingPermissions: "This Play requires the following permissions"
doYouWantToAllowThisPlayToAccessYourAccount: "Do you want to allow this Play to access your account?"
translateProfile: "Translate profile"
nsfwOpenBehavior: "NSFW media open behavior"
_vibrations:
click: "When an element is clicked"
note: "When a new note is posted on the timeline"
Expand Down Expand Up @@ -2522,3 +2523,6 @@ _imageCompressionMode:
noResizeCompress: "Compression without resize"
resizeCompressLossy: "Resize and lossy compression"
noResizeCompressLossy: "Lossy compression without resize"
_nsfwOpenBehavior:
click: "Click to open"
doubleClick: "Double click to open"
5 changes: 5 additions & 0 deletions locales/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1252,6 +1252,7 @@ export interface Locale {
"thisFlashRequiresTheFollowingPermissions": string;
"doYouWantToAllowThisPlayToAccessYourAccount": string;
"translateProfile": string;
"nsfwOpenBehavior": string;
"_vibrations": {
"click": string;
"note": string;
Expand Down Expand Up @@ -2712,6 +2713,10 @@ export interface Locale {
};
};
};
"_nsfwOpenBehavior": {
"click": string;
"doubleClick": string;
};
}
declare const locales: {
[lang: string]: Locale;
Expand Down
5 changes: 5 additions & 0 deletions locales/ja-JP.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1249,6 +1249,7 @@ additionalPermissionsForFlash: "Playへの追加許可"
thisFlashRequiresTheFollowingPermissions: "このPlayは以下の権限を要求しています"
doYouWantToAllowThisPlayToAccessYourAccount: "このPlayによるアカウントへのアクセスを許可しますか?"
translateProfile: "プロフィールを翻訳する"
nsfwOpenBehavior: "閲覧注意の開き方"

_vibrations:
click: "要素をクリックしたとき"
Expand Down Expand Up @@ -2607,3 +2608,7 @@ _externalResourceInstaller:
_themeInstallFailed:
title: "テーマのインストールに失敗しました"
description: "テーマのインストール中に問題が発生しました。もう一度お試しください。エラーの詳細はJavascriptコンソールをご覧ください。"

_nsfwOpenBehavior:
click: "タップして開く"
doubleClick: "二回タップして開く"
4 changes: 4 additions & 0 deletions locales/ko-KR.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1223,6 +1223,7 @@ additionalPermissionsForFlash: "Play에 대한 추가 권한"
thisFlashRequiresTheFollowingPermissions: "이 Play는 다음 권한을 요구해요"
doYouWantToAllowThisPlayToAccessYourAccount: "이 Play가 계정에 접근하도록 허용할까요?"
translateProfile: "프로필 번역하기"
nsfwOpenBehavior: "열람주의 여는 방법"
_vibrations:
click: "요소를 클릭했을 때"
note: "타임라인에 새 노트가 올라왔을 때"
Expand Down Expand Up @@ -2447,3 +2448,6 @@ _externalResourceInstaller:
_themeInstallFailed:
title: "테마 설치에 실패했어요"
description: "테마를 설치하는 동안 문제가 발생했어요. 다시 시도해 주세요. 오류에 대한 자세한 내용은 자바스크립트 콘솔을 참고해 주세요."
_nsfwOpenBehavior:
click: "탭하여 열기"
doubleClick: "더블 탭 하여 열기"
26 changes: 21 additions & 5 deletions packages/frontend/src/components/MkMediaImage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ SPDX-License-Identifier: AGPL-3.0-only
-->

<template>
<div :class="[hide ? $style.hidden : $style.visible, (image.isSensitive && defaultStore.state.highlightSensitiveMedia) && $style.sensitive]" :style="darkMode ? '--c: rgb(255 255 255 / 2%);' : '--c: rgb(0 0 0 / 2%);'" @click="onclick">
<div :data-is-hidden="hide ? 'true' : 'false'" :class="[hide ? $style.hidden : $style.visible, (image.isSensitive && defaultStore.state.highlightSensitiveMedia) && $style.sensitive]" :style="darkMode ? '--c: rgb(255 255 255 / 2%);' : '--c: rgb(0 0 0 / 2%);'" @click="onClick" @dblclick="onDblclick">
<component
:is="disableImageLink ? 'div' : 'a'"
v-bind="disableImageLink ? {
:is="(disableImageLink || hide) ? 'div' : 'a'"
v-bind="(disableImageLink || hide) ? {
title: image.name,
class: $style.imageContainer,
} : {
Expand Down Expand Up @@ -64,6 +64,7 @@ import { defaultStore } from '@/store.js';
import { i18n } from '@/i18n.js';
import * as os from '@/os.js';
import { iAmModerator } from '@/account.js';
import MkRippleEffect from '@/components/MkRippleEffect.vue';

const props = withDefaults(defineProps<{
image: Misskey.entities.DriveFile;
Expand All @@ -90,11 +91,24 @@ const url = $computed(() => (props.raw || defaultStore.state.loadRawImages)
: props.image.thumbnailUrl,
);

function onclick() {
function onClick(ev: MouseEvent) {
if (!props.controls) {
return;
}
if (hide) {
if (!hide) return;
if (defaultStore.state.nsfwOpenBehavior === 'doubleClick') {
os.popup(MkRippleEffect, { x: ev.clientX, y: ev.clientY }, {}, 'end');
}
if (defaultStore.state.nsfwOpenBehavior === 'click') {
hide = false;
}
}

function onDblclick() {
if (!props.controls) {
return;
}
if (hide && defaultStore.state.nsfwOpenBehavior === 'doubleClick') {
hide = false;
}
}
Expand Down Expand Up @@ -150,6 +164,7 @@ onUnmounted(() => {
<style lang="scss" module>
.hidden {
position: relative;
-webkit-tap-highlight-color: transparent;
}

.sensitive {
Expand Down Expand Up @@ -205,6 +220,7 @@ onUnmounted(() => {

.visible {
position: relative;
-webkit-tap-highlight-color: transparent;
//box-shadow: 0 0 0 1px var(--divider) inset;
background: var(--bg);
background-image: linear-gradient(45deg, var(--c) 16.67%, var(--bg) 16.67%, var(--bg) 50%, var(--c) 50%, var(--c) 66.67%, var(--bg) 66.67%, var(--bg) 100%);
Expand Down
8 changes: 8 additions & 0 deletions packages/frontend/src/components/MkMediaList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,14 @@ onMounted(() => {
itemData.thumbCropped = true;
});

// prevent to open hidden media
lightbox.addFilter('clickedIndex', (clickedIndex) => {
if ((gallery.value?.children[clickedIndex] as HTMLElement|undefined)?.dataset.isHidden === 'true') {
return -1;
}
return clickedIndex;
});

lightbox.on('uiRegister', () => {
lightbox.pswp.ui.registerElement({
name: 'altText',
Expand Down
17 changes: 15 additions & 2 deletions packages/frontend/src/components/MkMediaVideo.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ SPDX-License-Identifier: AGPL-3.0-only
-->

<template>
<div v-if="hide" :class="[$style.hidden, (video.isSensitive && defaultStore.state.highlightSensitiveMedia) && $style.sensitiveContainer]" @click="hide = false">
<div v-if="hide" :class="[$style.hidden, (video.isSensitive && defaultStore.state.highlightSensitiveMedia) && $style.sensitiveContainer]" data-is-hidden="true" @click="onClick" @dblclick="defaultStore.state.nsfwOpenBehavior === 'doubleClick' ? hide = false : ''">
<!-- 【注意】dataSaverMode が有効になっている際には、hide が false になるまでサムネイルや動画を読み込まないようにすること -->
<div :class="$style.sensitive">
<b v-if="video.isSensitive" style="display: block;"><i class="ti ti-alert-triangle"></i> {{ i18n.ts.sensitive }}{{ defaultStore.state.enableDataSaverMode ? ` (${i18n.ts.video}${video.size ? ' ' + bytes(video.size) : ''})` : '' }}</b>
<b v-else style="display: block;"><i class="ti ti-movie"></i> {{ defaultStore.state.enableDataSaverMode && video.size ? bytes(video.size) : i18n.ts.video }}</b>
<span>{{ i18n.ts.clickToShow }}</span>
</div>
</div>
<div v-else :class="[$style.visible, (video.isSensitive && defaultStore.state.highlightSensitiveMedia) && $style.sensitiveContainer]">
<div v-else :class="[$style.visible, (video.isSensitive && defaultStore.state.highlightSensitiveMedia) && $style.sensitiveContainer]" data-is-hidden="false">
<video
ref="videoEl"
:class="$style.video"
Expand All @@ -37,13 +37,25 @@ import * as Misskey from 'cherrypick-js';
import bytes from '@/filters/bytes.js';
import { defaultStore } from '@/store.js';
import { i18n } from '@/i18n.js';
import * as os from '@/os.js';
import MkRippleEffect from '@/components/MkRippleEffect.vue';

const props = defineProps<{
video: Misskey.entities.DriveFile;
}>();

const hide = ref((defaultStore.state.nsfw === 'force' || defaultStore.state.enableDataSaverMode) ? true : (props.video.isSensitive && defaultStore.state.nsfw !== 'ignore'));

function onClick(ev: MouseEvent) {
if (!hide.value) return;
if (defaultStore.state.nsfwOpenBehavior === 'doubleClick') {
os.popup(MkRippleEffect, { x: ev.clientX, y: ev.clientY }, {}, 'end');
}
if (defaultStore.state.nsfwOpenBehavior === 'click') {
hide.value = false;
}
}

const videoEl = shallowRef<HTMLVideoElement>();

watch(videoEl, () => {
Expand Down Expand Up @@ -107,6 +119,7 @@ watch(videoEl, () => {
align-items: center;
background: #111;
color: #fff;
-webkit-tap-highlight-color: transparent;
}

.sensitive {
Expand Down
7 changes: 7 additions & 0 deletions packages/frontend/src/pages/settings/general.vue
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,12 @@ SPDX-License-Identifier: AGPL-3.0-only
<option value="force">{{ i18n.ts._displayOfSensitiveMedia.force }}</option>
</MkSelect>

<MkSelect v-model="nsfwOpenBehavior">
<template #label>{{ i18n.ts.nsfwOpenBehavior }} <span class="_beta">CherryPick</span></template>
<option value="click">{{ i18n.ts._nsfwOpenBehavior.click }}</option>
<option value="doubleClick">{{ i18n.ts._nsfwOpenBehavior.doubleClick }}</option>
</MkSelect>

<MkRadios v-model="mediaListWithOneImageAppearance">
<template #label>{{ i18n.ts.mediaListWithOneImageAppearance }}</template>
<option value="expand">{{ i18n.ts.default }}</option>
Expand Down Expand Up @@ -381,6 +387,7 @@ const renoteQuoteButtonSeparation = computed(defaultStore.makeGetterSetter('reno
const showFixedPostFormInReplies = computed(defaultStore.makeGetterSetter('showFixedPostFormInReplies'));
const showingAnimatedImages = computed(defaultStore.makeGetterSetter('showingAnimatedImages'));
const allMediaNoteCollapse = computed(defaultStore.makeGetterSetter('allMediaNoteCollapse'));
const nsfwOpenBehavior = computed(defaultStore.makeGetterSetter('nsfwOpenBehavior'));

watch(lang, () => {
miLocalStorage.setItem('lang', lang.value as string);
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 @@ -477,6 +477,10 @@ export const defaultStore = markRaw(new Storage('base', {
where: 'device',
default: false,
},
nsfwOpenBehavior: {
where: 'device',
default: 'click' as 'click' | 'doubleClick',
},

// - Settings/Timeline
enableHomeTimeline: {
Expand Down

0 comments on commit 1dc0f88

Please sign in to comment.