diff --git a/CHANGELOG_CHERRYPICK.md b/CHANGELOG_CHERRYPICK.md index 2cdc4822ed..edbb70d7ab 100644 --- a/CHANGELOG_CHERRYPICK.md +++ b/CHANGELOG_CHERRYPICK.md @@ -45,6 +45,7 @@ Misskey의 전체 변경 사항을 확인하려면, [CHANGELOG.md#2023xx](CHANGE - Revert: 사용자 통계 표시 기능 제거 ([MisskeyIO/misskey@114c7fe6](https://github.com/MisskeyIO/misskey/commit/114c7fe6b37dd6bddbcd9d92406f8b13bf688e8b)) ### Client +- Feat: 데이터 절약 모드로 코드 하이라이트 로드를 줄일 수 있음 (misskey-dev/misskey#12526) - Enhance: 사운드 설정을 기본값으로 복원하거나 저장할 때 확실하게 표시함 - Enhance: 리모트 서버와 동일한 이모지가 존재하지 않는 경우 '이모지 복사'를 비활성화함 - Enhance: 아이콘 장식을 바로 업로드 하거나 드라이브에서 불러올 수 있음 ([Secineralyr/misskey.dream@e358212d](https://github.com/Secineralyr/misskey.dream/commit/e358212da93256749e31d9e0ca9dd2ed37fd548e), [Secineralyr/misskey.dream@52592fea](https://github.com/Secineralyr/misskey.dream/commit/52592fea52684497ba7e07f173aac2b1083afcb1)) @@ -52,6 +53,8 @@ Misskey의 전체 변경 사항을 확인하려면, [CHANGELOG.md#2023xx](CHANGE - Enhance: 진동 개선 - 진동을 사용할 수 없는 환경에서 스위치를 조작할 수 없도록 비활성화 - 진동을 사용할 수 없는 이유를 보다 명확하게 표시하도록 개선 +- Enhance: 데이터 절약 모드 적용 범위를 개별적으로 설정할 수 있음 (misskey-dev/misskey#12526) + - 기존 데이터 절약 모드 설정이 재설정됩니다. - Fix: '모달 배경색 제거' 옵션이 이모지 피커에 반영되지 않음 - Fix: 열람 주의로 설정된 노트의 반응이 더 보기를 눌러야 표시됨 diff --git a/locales/en-US.yml b/locales/en-US.yml index 3428b9e793..e533b740e3 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -1268,6 +1268,8 @@ useGroupedNotifications: "Display grouped notifications" signupPendingError: "There was a problem verifying the email address. The link may have expired." cwNotationRequired: "If \"Hide content\" is enabled, a description must be provided." doReaction: "Add reaction" +code: "Code" +tryReloadIfNotApplied: "If the settings are not reflected, please try refresh." showUnreadNotificationsCount: "Show the number of unread notifications" showCatOnly: "Show only cats" additionalPermissionsForFlash: "Allow to add permission to Play" @@ -2623,3 +2625,16 @@ _imageCompressionMode: noResizeCompress: "Compression without resize" resizeCompressLossy: "Resize and lossy compression" noResizeCompressLossy: "Lossy compression without resize" +_dataSaver: + _media: + title: "Load media" + description: "Prevents images/videos from being loaded automatically. Hidden images/videos will be loaded when tapped." + _avatar: + title: "User icon image" + description: "Animation of user's icon images stops. Since animated images can be larger in file size than normal images, data traffic can be further reduced." + _urlPreview: + title: "URL preview thumbnail" + description: "URL preview thumbnail images will no longer load." + _code: + title: "Code Highlights" + description: "If code highlighting notation is used, such as MFM, it will not be loaded until tapped. Code highlighting requires loading the definition file for each language to be highlighted, but since these files are no longer loaded automatically, a reduction in communication volume can be expected." diff --git a/locales/index.d.ts b/locales/index.d.ts index b1f50e1689..93b16141a8 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -1277,6 +1277,8 @@ export interface Locale { "signupPendingError": string; "cwNotationRequired": string; "doReaction": string; + "code": string; + "tryReloadIfNotApplied": string; "showUnreadNotificationsCount": string; "showCatOnly": string; "additionalPermissionsForFlash": string; @@ -2850,6 +2852,24 @@ export interface Locale { "resizeCompressLossy": string; "noResizeCompressLossy": string; }; + "_dataSaver": { + "_media": { + "title": string; + "description": string; + }; + "_avatar": { + "title": string; + "description": string; + }; + "_urlPreview": { + "title": string; + "description": string; + }; + "_code": { + "title": string; + "description": string; + }; + }; } declare const locales: { [lang: string]: Locale; diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 707cc3ed88..b824b7f3a1 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -1274,6 +1274,8 @@ useGroupedNotifications: "通知をグルーピングして表示する" signupPendingError: "メールアドレスの確認中に問題が発生しました。リンクの有効期限が切れている可能性があります。" cwNotationRequired: "「内容を隠す」がオンの場合は注釈の記述が必要です。" doReaction: "リアクションする" +code: "コード" +tryReloadIfNotApplied: "設定が反映されない場合はリロードをお試しください。" showUnreadNotificationsCount: "未読の通知の数を表示する" showCatOnly: "キャット付きのみ" additionalPermissionsForFlash: "Playへの追加許可" @@ -2733,3 +2735,17 @@ _imageCompressionMode: noResizeCompress: "縮小せず再圧縮する" resizeCompressLossy: "縮小して非可逆圧縮する" noResizeCompressLossy: "縮小せず非可逆圧縮する" + +_dataSaver: + _media: + title: "メディアの読み込み" + description: "画像・動画が自動で読み込まれるのを防止します。隠れている画像・動画はタップすると読み込まれます。" + _avatar: + title: "アイコン画像" + description: "アイコン画像のアニメーションが停止します。アニメーション画像は通常の画像よりファイルサイズが大きいことがあるので、データ通信量をさらに削減できます。" + _urlPreview: + title: "URLプレビューのサムネイル" + description: "URLプレビューのサムネイル画像が読み込まれなくなります。" + _code: + title: "コードハイライト" + description: "MFMなどでコードハイライト記法が使われている場合、タップするまで読み込まれなくなります。コードハイライトではハイライトする言語ごとにその定義ファイルを読み込む必要がありますが、それらが自動で読み込まれなくなるため、通信量の削減が見込めます。" diff --git a/locales/ko-KR.yml b/locales/ko-KR.yml index 4a0c8a9999..587874062b 100644 --- a/locales/ko-KR.yml +++ b/locales/ko-KR.yml @@ -1264,6 +1264,8 @@ useGroupedNotifications: "알림을 묶어서 표시" signupPendingError: "메일 주소 확인중에 문제가 발생했어요. 링크의 유효기간이 지났을 수도 있어요." cwNotationRequired: "'내용 숨기기'를 체크했을 경우 주석을 작성해야 해요." doReaction: "리액션 추가" +code: "코드" +tryReloadIfNotApplied: "설정이 반영되지 않으면 새로 고침을 시도해 보세요." showUnreadNotificationsCount: "읽지 않은 알림 수 표시" showCatOnly: "고양이만 보기" additionalPermissionsForFlash: "Play에 대한 추가 권한" @@ -2620,3 +2622,16 @@ _imageCompressionMode: noResizeCompress: "해상도를 축소하지 않고 압축" resizeCompressLossy: "해상도 축소 및 손실 압축" noResizeCompressLossy: "해상도를 축소하지 않고 손실 압축" +_dataSaver: + _media: + title: "미디어 불러오기" + description: "이미지/동영상이 자동으로 로드되는 것을 방지해요. 탭하면 숨겨진 이미지/동영상을 불러올 수 있어요." + _avatar: + title: "프로필 아이콘" + description: "움직이는 프로필 아이콘이 정적 이미지로 변경되어 표시돼요. 움직이는 이미지는 일반 이미지보다 파일 크기가 클 수 있기 때문에 데이터 통신량을 더욱 줄일 수 있어요." + _urlPreview: + title: "URL 미리보기 썸네일" + description: "URL 미리보기의 썸네일 이미지를 불러오지 않아요." + _code: + title: "코드 하이라이트" + description: "MFM 등에서 코드 하이라이트 기법을 사용하는 경우, 탭하기 전까지는 코드 하이라이트를 불러오지 않아요. 코드 하이라이트는 강조할 언어마다 해당 정의 파일을 불러와야 하지만, 이를 자동으로 불러오지 않기 때문에 통신량 감소를 기대할 수 있어요." diff --git a/packages/frontend/src/components/MkCode.core.vue b/packages/frontend/src/components/MkCode.core.vue index 232a8b66e4..a6d61ab719 100644 --- a/packages/frontend/src/components/MkCode.core.vue +++ b/packages/frontend/src/components/MkCode.core.vue @@ -62,7 +62,7 @@ watch(() => props.lang, (to) => { padding: 1em; margin: .5em 0; overflow: auto; - border-radius: .3em; + border-radius: 8px; & pre, & code { diff --git a/packages/frontend/src/components/MkCode.vue b/packages/frontend/src/components/MkCode.vue index 38a40f4dd5..63fc4e652b 100644 --- a/packages/frontend/src/components/MkCode.vue +++ b/packages/frontend/src/components/MkCode.vue @@ -9,13 +9,21 @@ SPDX-License-Identifier: AGPL-3.0-only {{ code }} - + + @@ -36,4 +46,25 @@ const XCode = defineAsyncComponent(() => import('@/components/MkCode.core.vue')) padding: .1em; border-radius: .3em; } + +.codePlaceholderRoot { + display: block; + width: 100%; + background: none; + border: none; + outline: none; + font: inherit; + cursor: pointer; + box-sizing: border-box; + border-radius: 8px; + padding: 24px; + margin-top: 4px; + color: #D4D4D4; + background: #1E1E1E; +} + +.codePlaceholderContainer { + text-align: center; + font-size: 0.8em; +} diff --git a/packages/frontend/src/components/MkMediaImage.vue b/packages/frontend/src/components/MkMediaImage.vue index a95d173ba5..59ef0b7225 100644 --- a/packages/frontend/src/components/MkMediaImage.vue +++ b/packages/frontend/src/components/MkMediaImage.vue @@ -19,7 +19,7 @@ SPDX-License-Identifier: AGPL-3.0-only >
- {{ i18n.ts.sensitive }}{{ defaultStore.state.enableDataSaverMode ? ` (${i18n.ts.image}${image.size ? ' ' + bytes(image.size) : ''})` : '' }} - {{ defaultStore.state.enableDataSaverMode && image.size ? bytes(image.size) : i18n.ts.image }} + {{ i18n.ts.sensitive }}{{ defaultStore.state.dataSaver.media ? ` (${i18n.ts.image}${image.size ? ' ' + bytes(image.size) : ''})` : '' }} + {{ defaultStore.state.dataSaver.media && image.size ? bytes(image.size) : i18n.ts.image }} {{ clickToShowMessage }}
@@ -86,7 +86,7 @@ if (defaultStore.state.showingAnimatedImages === 'interaction') playAnimation = let playAnimationTimer = setTimeout(() => playAnimation = false, 5000); const url = $computed(() => (props.raw || defaultStore.state.loadRawImages) ? props.image.url - : (defaultStore.state.disableShowingAnimatedImages || defaultStore.state.enableDataSaverMode) || (['interaction', 'inactive'].includes(defaultStore.state.showingAnimatedImages) && !playAnimation) + : (defaultStore.state.disableShowingAnimatedImages || defaultStore.state.dataSaver.media) || (['interaction', 'inactive'].includes(defaultStore.state.showingAnimatedImages) && !playAnimation) ? getStaticImageUrl(props.image.url) : props.image.thumbnailUrl, ); @@ -127,7 +127,7 @@ function resetTimer() { // Plugin:register_note_view_interruptor を使って書き換えられる可能性があるためwatchする watch(() => props.image, () => { - hide = (defaultStore.state.nsfw === 'force' || defaultStore.state.enableDataSaverMode) ? true : (props.image.isSensitive && defaultStore.state.nsfw !== 'ignore'); + hide = (defaultStore.state.nsfw === 'force' || defaultStore.state.dataSaver.media) ? true : (props.image.isSensitive && defaultStore.state.nsfw !== 'ignore'); }, { deep: true, immediate: true, diff --git a/packages/frontend/src/components/MkMediaVideo.vue b/packages/frontend/src/components/MkMediaVideo.vue index 050aa48020..2b5da835f2 100644 --- a/packages/frontend/src/components/MkMediaVideo.vue +++ b/packages/frontend/src/components/MkMediaVideo.vue @@ -7,8 +7,8 @@ SPDX-License-Identifier: AGPL-3.0-only
- {{ i18n.ts.sensitive }}{{ defaultStore.state.enableDataSaverMode ? ` (${i18n.ts.video}${video.size ? ' ' + bytes(video.size) : ''})` : '' }} - {{ defaultStore.state.enableDataSaverMode && video.size ? bytes(video.size) : i18n.ts.video }} + {{ i18n.ts.sensitive }}{{ defaultStore.state.dataSaver.media ? ` (${i18n.ts.video}${video.size ? ' ' + bytes(video.size) : ''})` : '' }} + {{ defaultStore.state.dataSaver.media && video.size ? bytes(video.size) : i18n.ts.video }} {{ clickToShowMessage }}
@@ -45,7 +45,7 @@ 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')); +const hide = ref((defaultStore.state.nsfw === 'force' || defaultStore.state.dataSaver.media) ? true : (props.video.isSensitive && defaultStore.state.nsfw !== 'ignore')); let clickToShowMessage = $computed(() => defaultStore.state.nsfwOpenBehavior === 'click' ? i18n.ts.clickToShow diff --git a/packages/frontend/src/components/MkMention.vue b/packages/frontend/src/components/MkMention.vue index 60cbb2b1c9..9394bfd092 100644 --- a/packages/frontend/src/components/MkMention.vue +++ b/packages/frontend/src/components/MkMention.vue @@ -51,7 +51,7 @@ const bgCss = bg.toRgbString(); let playAnimation = $ref(true); if (defaultStore.state.showingAnimatedImages === 'interaction') playAnimation = false; let playAnimationTimer = setTimeout(() => playAnimation = false, 5000); -const avatarUrl = $computed(() => (defaultStore.state.disableShowingAnimatedImages || defaultStore.state.enableDataSaverMode) || (['interaction', 'inactive'].includes(defaultStore.state.showingAnimatedImages) && !playAnimation) +const avatarUrl = $computed(() => (defaultStore.state.disableShowingAnimatedImages || defaultStore.state.dataSaver.avatar) || (['interaction', 'inactive'].includes(defaultStore.state.showingAnimatedImages) && !playAnimation) ? getStaticImageUrl(`/avatar/@${props.username}@${props.host}`) : `/avatar/@${props.username}@${props.host}`, ); diff --git a/packages/frontend/src/components/MkUrlPreview.vue b/packages/frontend/src/components/MkUrlPreview.vue index 7fbed7627c..3338725801 100644 --- a/packages/frontend/src/components/MkUrlPreview.vue +++ b/packages/frontend/src/components/MkUrlPreview.vue @@ -45,7 +45,7 @@ SPDX-License-Identifier: AGPL-3.0-only
-
+
diff --git a/packages/frontend/src/components/global/CPAvatar-Friendly.vue b/packages/frontend/src/components/global/CPAvatar-Friendly.vue index 53efeddd8e..56d5c83255 100644 --- a/packages/frontend/src/components/global/CPAvatar-Friendly.vue +++ b/packages/frontend/src/components/global/CPAvatar-Friendly.vue @@ -94,7 +94,7 @@ const bound = $computed(() => props.link let playAnimation = $ref(true); if (defaultStore.state.showingAnimatedImages === 'interaction') playAnimation = false; let playAnimationTimer = setTimeout(() => playAnimation = false, 5000); -const url = $computed(() => (defaultStore.state.disableShowingAnimatedImages || defaultStore.state.enableDataSaverMode) || (['interaction', 'inactive'].includes(defaultStore.state.showingAnimatedImages) && !playAnimation) +const url = $computed(() => (defaultStore.state.disableShowingAnimatedImages || defaultStore.state.dataSaver.avatar) || (['interaction', 'inactive'].includes(defaultStore.state.showingAnimatedImages) && !playAnimation) ? getStaticImageUrl(props.user.avatarUrl) : props.user.avatarUrl); diff --git a/packages/frontend/src/components/global/MkAvatar.vue b/packages/frontend/src/components/global/MkAvatar.vue index a3ff313ee1..445b7c068e 100644 --- a/packages/frontend/src/components/global/MkAvatar.vue +++ b/packages/frontend/src/components/global/MkAvatar.vue @@ -117,7 +117,7 @@ const bound = $computed(() => props.link let playAnimation = $ref(true); if (defaultStore.state.showingAnimatedImages === 'interaction') playAnimation = false; let playAnimationTimer = setTimeout(() => playAnimation = false, 5000); -const url = $computed(() => (defaultStore.state.disableShowingAnimatedImages || defaultStore.state.enableDataSaverMode) || (['interaction', 'inactive'].includes(defaultStore.state.showingAnimatedImages) && !playAnimation) +const url = $computed(() => (defaultStore.state.disableShowingAnimatedImages || defaultStore.state.dataSaver.avatar) || (['interaction', 'inactive'].includes(defaultStore.state.showingAnimatedImages) && !playAnimation) ? getStaticImageUrl(props.user.avatarUrl) : props.user.avatarUrl); diff --git a/packages/frontend/src/components/global/ToastAvatar.vue b/packages/frontend/src/components/global/ToastAvatar.vue index a0fc9bc77c..520f8aecf2 100644 --- a/packages/frontend/src/components/global/ToastAvatar.vue +++ b/packages/frontend/src/components/global/ToastAvatar.vue @@ -93,7 +93,7 @@ const bound = $computed(() => props.link let playAnimation = $ref(true); if (defaultStore.state.showingAnimatedImages === 'interaction') playAnimation = false; let playAnimationTimer = setTimeout(() => playAnimation = false, 5000); -const url = $computed(() => (defaultStore.state.disableShowingAnimatedImages || defaultStore.state.enableDataSaverMode) || (['interaction', 'inactive'].includes(defaultStore.state.showingAnimatedImages) && !playAnimation) +const url = $computed(() => (defaultStore.state.disableShowingAnimatedImages || defaultStore.state.dataSaver.avatar) || (['interaction', 'inactive'].includes(defaultStore.state.showingAnimatedImages) && !playAnimation) ? getStaticImageUrl(props.user.avatarUrl) : props.user.avatarUrl); diff --git a/packages/frontend/src/pages/settings/general.vue b/packages/frontend/src/pages/settings/general.vue index adb6c3fe5f..6679e59bbe 100644 --- a/packages/frontend/src/pages/settings/general.vue +++ b/packages/frontend/src/pages/settings/general.vue @@ -155,7 +155,6 @@ SPDX-License-Identifier: AGPL-3.0-only {{ i18n.ts.disableDrawer }} {{ i18n.ts.forceShowAds }} {{ i18n.ts.showUnreadNotificationsCount }} - {{ i18n.ts.dataSaver }}
@@ -274,6 +273,37 @@ SPDX-License-Identifier: AGPL-3.0-only
+ + + +
+ {{ i18n.ts.tryReloadIfNotApplied }} + +
+ {{ i18n.ts.enableAll }} + {{ i18n.ts.disableAll }} +
+
+ + {{ i18n.ts._dataSaver._media.title }} + + + + {{ i18n.ts._dataSaver._avatar.title }} + + + + {{ i18n.ts._dataSaver._urlPreview.title }} + + + + {{ i18n.ts._dataSaver._code.title }} + + +
+
+
+ @@ -304,6 +334,7 @@ import MkButton from '@/components/MkButton.vue'; import FormSection from '@/components/form/section.vue'; import FormLink from '@/components/form/link.vue'; import MkLink from '@/components/MkLink.vue'; +import MkInfo from '@/components/MkInfo.vue'; import { langs } from '@/config.js'; import { defaultStore } from '@/store.js'; import * as os from '@/os.js'; @@ -313,11 +344,11 @@ import { definePageMetadata } from '@/scripts/page-metadata.js'; import { miLocalStorage } from '@/local-storage.js'; import { globalEvents } from '@/events.js'; import { claimAchievement } from '@/scripts/achievements.js'; -import MkInfo from '@/components/MkInfo.vue'; const lang = ref(miLocalStorage.getItem('lang')); // const fontSize = ref(miLocalStorage.getItem('fontSize')); const useSystemFont = ref(miLocalStorage.getItem('useSystemFont') != null); +const dataSaver = ref(defaultStore.state.dataSaver); const fontSizeBefore = ref(miLocalStorage.getItem('fontSize')); const useBoldFont = ref(miLocalStorage.getItem('useBoldFont')); @@ -354,7 +385,6 @@ const disableShowingAnimatedImages = computed(defaultStore.makeGetterSetter('dis const forceShowAds = computed(defaultStore.makeGetterSetter('forceShowAds')); const loadRawImages = computed(defaultStore.makeGetterSetter('loadRawImages')); const highlightSensitiveMedia = computed(defaultStore.makeGetterSetter('highlightSensitiveMedia')); -const enableDataSaverMode = computed(defaultStore.makeGetterSetter('enableDataSaverMode')); const imageNewTab = computed(defaultStore.makeGetterSetter('imageNewTab')); const nsfw = computed(defaultStore.makeGetterSetter('nsfw')); const showFixedPostForm = computed(defaultStore.makeGetterSetter('showFixedPostForm')); @@ -440,7 +470,6 @@ watch([ keepScreenOn, disableStreamingTimeline, showUnreadNotificationsCount, - enableDataSaverMode, enableAbsoluteTime, enableMarkByDate, showSubNoteFooterButton, @@ -528,6 +557,24 @@ function testNotification(): void { }, 300); } +function enableAllDataSaver() { + const g = defaultStore.state.dataSaver; + Object.keys(g).forEach((key) => { g[key] = true; }); + dataSaver.value = g; +} + +function disableAllDataSaver() { + const g = defaultStore.state.dataSaver; + Object.keys(g).forEach((key) => { g[key] = false; }); + dataSaver.value = g; +} + +watch(dataSaver, (to) => { + defaultStore.set('dataSaver', to); +}, { + deep: true, +}); + onMounted(() => { if (fontSizeBefore.value == null) { fontSizeBefore.value = fontSize.value as string; diff --git a/packages/frontend/src/pages/settings/preferences-backups.vue b/packages/frontend/src/pages/settings/preferences-backups.vue index 3769cfcb46..700397ea9b 100644 --- a/packages/frontend/src/pages/settings/preferences-backups.vue +++ b/packages/frontend/src/pages/settings/preferences-backups.vue @@ -71,7 +71,7 @@ const defaultStoreSaveKeys: (keyof typeof defaultStore['state'])[] = [ 'advancedMfm', 'loadRawImages', 'imageNewTab', - 'enableDataSaverMode', + 'dataSaver', 'disableShowingAnimatedImages', 'showingAnimatedImages', 'emojiStyle', diff --git a/packages/frontend/src/pages/user/index.files.vue b/packages/frontend/src/pages/user/index.files.vue index 4b4241a764..9576628179 100644 --- a/packages/frontend/src/pages/user/index.files.vue +++ b/packages/frontend/src/pages/user/index.files.vue @@ -69,7 +69,7 @@ if (defaultStore.state.showingAnimatedImages === 'interaction') playAnimation = let playAnimationTimer = setTimeout(() => playAnimation = false, 5000); function thumbnail(image: Misskey.entities.DriveFile): string { - return (defaultStore.state.disableShowingAnimatedImages || defaultStore.state.enableDataSaverMode) || (['interaction', 'inactive'].includes(defaultStore.state.showingAnimatedImages) && !playAnimation) + return (defaultStore.state.disableShowingAnimatedImages || defaultStore.state.dataSaver.media) || (['interaction', 'inactive'].includes(defaultStore.state.showingAnimatedImages) && !playAnimation) ? getStaticImageUrl(image.url) : image.thumbnailUrl; } diff --git a/packages/frontend/src/store.ts b/packages/frontend/src/store.ts index f1229908b6..6cbe8db0b6 100644 --- a/packages/frontend/src/store.ts +++ b/packages/frontend/src/store.ts @@ -232,10 +232,6 @@ export const defaultStore = markRaw(new Storage('base', { where: 'device', default: false, }, - enableDataSaverMode: { - where: 'device', - default: false, - }, disableShowingAnimatedImages: { where: 'device', default: window.matchMedia('(prefers-reduced-motion)').matches, @@ -424,6 +420,15 @@ export const defaultStore = markRaw(new Storage('base', { where: 'deviceAccount', default: false, }, + dataSaver: { + where: 'device', + default: { + media: false, + avatar: false, + urlPreview: false, + code: false, + } as Record, + }, sound_masterVolume: { where: 'device', diff --git a/packages/frontend/src/widgets/WidgetPhotos.vue b/packages/frontend/src/widgets/WidgetPhotos.vue index 05df664760..ba5ceef5d4 100644 --- a/packages/frontend/src/widgets/WidgetPhotos.vue +++ b/packages/frontend/src/widgets/WidgetPhotos.vue @@ -75,7 +75,7 @@ let playAnimation = $ref(true); if (defaultStore.state.showingAnimatedImages === 'interaction') playAnimation = false; let playAnimationTimer = setTimeout(() => playAnimation = false, 5000); const thumbnail = (image: any): string => { - return (defaultStore.state.disableShowingAnimatedImages || defaultStore.state.enableDataSaverMode) || (['interaction', 'inactive'].includes(defaultStore.state.showingAnimatedImages) && !playAnimation) + return (defaultStore.state.disableShowingAnimatedImages || defaultStore.state.dataSaver.media) || (['interaction', 'inactive'].includes(defaultStore.state.showingAnimatedImages) && !playAnimation) ? getStaticImageUrl(image.url) : image.thumbnailUrl; }; diff --git a/packages/frontend/test/init.ts b/packages/frontend/test/init.ts index 1e17d0f3b0..0dd5e62a3d 100644 --- a/packages/frontend/test/init.ts +++ b/packages/frontend/test/init.ts @@ -21,7 +21,17 @@ vi.stubGlobal('WebSocket', class WebSocket extends EventTarget { static CLOSING vi.mock('@/store.js', () => { return { defaultStore: { - state: {}, + state: { + + // なんかtestがうまいこと動かないのでここに書く + dataSaver: { + media: false, + avatar: false, + urlPreview: false, + code: false, + }, + + }, }, }; });