Skip to content

Commit

Permalink
fix(frontend): vue v3.4.16でタイムラインが正常に表示できない問題を修正
Browse files Browse the repository at this point in the history
  • Loading branch information
kakkokari-gtyih committed Feb 11, 2024
1 parent 207e4f3 commit 92b2165
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 30 deletions.
56 changes: 29 additions & 27 deletions packages/frontend/src/pages/timeline.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template #header><MkPageHeader v-model:tab="src" :actions="headerActions" :tabs="$i ? headerTabs : headerTabsWhenNotLogin" :displayMyAvatar="true"/></template>
<MkSpacer :contentMax="800">
<MkHorizontalSwipe v-model:tab="src" :tabs="$i ? headerTabs : headerTabsWhenNotLogin">
<div :key="src + withRenotes + withReplies + onlyFiles" ref="rootEl" v-hotkey.global="keymap">
<div :key="src" ref="rootEl" v-hotkey.global="keymap">
<MkInfo v-if="['home', 'local', 'social', 'global'].includes(src) && !defaultStore.reactiveState.timelineTutorials.value[src]" style="margin-bottom: var(--margin);" closable @close="closeTutorial()">
{{ i18n.ts._timelineDescription[src] }}
</MkInfo>
Expand Down Expand Up @@ -50,6 +50,7 @@ import { $i } from '@/account.js';
import { definePageMetadata } from '@/scripts/page-metadata.js';
import { antennasCache, userListsCache } from '@/cache.js';
import { deviceKind } from '@/scripts/device-kind.js';
import { deepMerge } from '@/scripts/merge.js';
import { MenuItem } from '@/types/menu.js';
import { miLocalStorage } from '@/local-storage.js';

Expand All @@ -74,41 +75,56 @@ const withRenotes = computed({
get: () => defaultStore.reactiveState.tl.value.filter.withRenotes,
set: (x: boolean) => saveTlFilter('withRenotes', x),
});
const withReplies = computed({

// computed内での無限ループを防ぐためのフラグ
const localSocialTLFilterSwitchStore = ref<'withReplies' | 'onlyFiles' | false>('withReplies');

const withReplies = computed<boolean>({
get: () => {
if (!$i) return false;
if (['local', 'social'].includes(src.value) && onlyFiles.value) {
if (['local', 'social'].includes(src.value) && localSocialTLFilterSwitchStore.value === 'onlyFiles') {
return false;
} else {
return defaultStore.reactiveState.tl.value.filter.withReplies;
}
},
set: (x: boolean) => saveTlFilter('withReplies', x),
});
const onlyFiles = computed({
const onlyFiles = computed<boolean>({
get: () => {
if (['local', 'social'].includes(src.value) && withReplies.value) {
if (['local', 'social'].includes(src.value) && localSocialTLFilterSwitchStore.value === 'withReplies') {
return false;
} else {
return defaultStore.reactiveState.tl.value.filter.onlyFiles;
}
},
set: (x: boolean) => saveTlFilter('onlyFiles', x),
});

watch([withReplies, onlyFiles], ([withRepliesTo, onlyFilesTo]) => {
if (withRepliesTo) {
localSocialTLFilterSwitchStore.value = 'withReplies';
} else if (onlyFilesTo) {
localSocialTLFilterSwitchStore.value = 'onlyFiles';
} else {
localSocialTLFilterSwitchStore.value = false;
}
});

const withSensitive = computed({
get: () => defaultStore.reactiveState.tl.value.filter.withSensitive,
set: (x: boolean) => {
saveTlFilter('withSensitive', x);

// これだけはクライアント側で完結する処理なので手動でリロード
tlComponent.value?.reloadTimeline();
},
set: (x: boolean) => saveTlFilter('withSensitive', x),
});

watch(src, () => {
queue.value = 0;
});

watch(withSensitive, () => {
// これだけはクライアント側で完結する処理なので手動でリロード
tlComponent.value?.reloadTimeline();
});

function queueUpdated(q: number): void {
queue.value = q;
}
Expand Down Expand Up @@ -184,10 +200,7 @@ async function chooseChannel(ev: MouseEvent): Promise<void> {
}

function saveSrc(newSrc: 'home' | 'local' | 'social' | 'global' | `list:${string}`): void {
const out = {
...defaultStore.state.tl,
src: newSrc,
};
const out = deepMerge({ src: newSrc }, defaultStore.state.tl);

if (newSrc.startsWith('userList:')) {
const id = newSrc.substring('userList:'.length);
Expand All @@ -200,20 +213,9 @@ function saveSrc(newSrc: 'home' | 'local' | 'social' | 'global' | `list:${string

function saveTlFilter(key: keyof typeof defaultStore.state.tl.filter, newValue: boolean) {
if (key !== 'withReplies' || $i) {
const out = { ...defaultStore.state.tl };
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (!out.filter) {
out.filter = {
withRenotes: true,
withReplies: true,
withSensitive: true,
onlyFiles: false,
};
}
out.filter[key] = newValue;
const out = deepMerge({ filter: { [key]: newValue } }, defaultStore.state.tl);
defaultStore.set('tl', out);
}
return newValue;
}

async function timetravel(): Promise<void> {
Expand Down
10 changes: 7 additions & 3 deletions packages/frontend/src/scripts/merge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
import { deepClone } from './clone.js';
import type { Cloneable } from './clone.js';

type DeepPartial<T> = {
[P in keyof T]?: T[P] extends Record<string | number | symbol, unknown> ? DeepPartial<T[P]> : T[P];
};

function isPureObject(value: unknown): value is Record<string | number | symbol, unknown> {
return typeof value === 'object' && value !== null && !Array.isArray(value);
}
Expand All @@ -14,18 +18,18 @@ function isPureObject(value: unknown): value is Record<string | number | symbol,
* valueにないキーをdefからもらう(再帰的)\
* nullはそのまま、undefinedはdefの値
**/
export function deepMerge<X extends Record<string | number | symbol, unknown>>(value: X, def: X): X {
export function deepMerge<X extends Record<string | number | symbol, unknown>>(value: DeepPartial<X>, def: X): X {
if (isPureObject(value) && isPureObject(def)) {
const result = deepClone(value as Cloneable) as X;
for (const [k, v] of Object.entries(def) as [keyof X, X[keyof X]][]) {
if (!Object.prototype.hasOwnProperty.call(value, k) || value[k] === undefined) {
result[k] = v;
} else if (isPureObject(v) && isPureObject(result[k])) {
const child = deepClone(result[k] as Cloneable) as X[keyof X] & Record<string | number | symbol, unknown>;
const child = deepClone(result[k] as Cloneable) as DeepPartial<X[keyof X] & Record<string | number | symbol, unknown>>;
result[k] = deepMerge<typeof v>(child, v);
}
}
return result;
}
return value;
throw new Error('deepMerge: value and def must be pure objects');
}

0 comments on commit 92b2165

Please sign in to comment.