1
0
forked from mirror/misskey

timelineBackTopBehavior

This commit is contained in:
tamaina 2023-07-26 12:22:26 +00:00
parent 9f79e494f5
commit 4785b9bfdd
7 changed files with 38 additions and 10 deletions

5
locales/index.d.ts vendored
View File

@ -1097,6 +1097,7 @@ export interface Locale {
"doYouAgree": string; "doYouAgree": string;
"beSureToReadThisAsItIsImportant": string; "beSureToReadThisAsItIsImportant": string;
"iHaveReadXCarefullyAndAgree": string; "iHaveReadXCarefullyAndAgree": string;
"timelineBackTopBehavior": string;
"_initialAccountSetting": { "_initialAccountSetting": {
"accountCreated": string; "accountCreated": string;
"letsStartAccountSetup": string; "letsStartAccountSetup": string;
@ -1637,6 +1638,10 @@ export interface Locale {
"dialog": string; "dialog": string;
"quiet": string; "quiet": string;
}; };
"_timelineBackTopBehavior": {
"newest": string;
"next": string;
};
"_channel": { "_channel": {
"create": string; "create": string;
"edit": string; "edit": string;

View File

@ -1094,6 +1094,7 @@ expired: "期限切れ"
doYouAgree: "同意しますか?" doYouAgree: "同意しますか?"
beSureToReadThisAsItIsImportant: "重要ですので必ずお読みください。" beSureToReadThisAsItIsImportant: "重要ですので必ずお読みください。"
iHaveReadXCarefullyAndAgree: "「{x}」の内容をよく読み、同意します。" iHaveReadXCarefullyAndAgree: "「{x}」の内容をよく読み、同意します。"
timelineBackTopBehavior: "タイムラインのスクロールが先頭に戻った時の挙動"
_initialAccountSetting: _initialAccountSetting:
accountCreated: "アカウントの作成が完了しました!" accountCreated: "アカウントの作成が完了しました!"
@ -1555,6 +1556,10 @@ _serverDisconnectedBehavior:
dialog: "ダイアログで警告" dialog: "ダイアログで警告"
quiet: "控えめに警告" quiet: "控えめに警告"
_timelineBackTopBehavior:
newest: "最新の投稿を表示"
next: "次の投稿を遡る"
_channel: _channel:
create: "チャンネルを作成" create: "チャンネルを作成"
edit: "チャンネルを編集" edit: "チャンネルを編集"

View File

@ -47,7 +47,7 @@ import MkButton from '@/components/MkButton.vue';
import { defaultStore } from '@/store'; import { defaultStore } from '@/store';
import { MisskeyEntity } from '@/types/date-separated-list'; import { MisskeyEntity } from '@/types/date-separated-list';
import { i18n } from '@/i18n'; import { i18n } from '@/i18n';
import { UAParser } from 'ua-parser-js'; import { isWebKit } from '@/scripts/useragent';
const SECOND_FETCH_LIMIT = 30; const SECOND_FETCH_LIMIT = 30;
const TOLERANCE = 6; const TOLERANCE = 6;
@ -94,8 +94,7 @@ function concatMapWithArray(map: MisskeyEntityMap, entities: MisskeyEntity[]): M
return new Map([...map, ...arrayToEntries(entities)]); return new Map([...map, ...arrayToEntries(entities)]);
} }
const ua = new UAParser(navigator.userAgent); const timelineBackTopBehavior = computed(() => isWebKit() ? 'newest' : defaultStore.reactiveState.timelineBackTopBehavior.value);
const isWebKit = ua.getEngine().name === 'WebKit';
</script> </script>
<script lang="ts" setup> <script lang="ts" setup>
import { infoImageUrl } from '@/instance'; import { infoImageUrl } from '@/instance';
@ -200,7 +199,7 @@ watch([$$(rootEl), $$(scrollObserver)], () => {
* weakBackedがtruefalseになったらexecuteQueue * weakBackedがtruefalseになったらexecuteQueue
*/ */
watch($$(weakBacked), () => { watch($$(weakBacked), () => {
if (!isWebKit && !weakBacked) { if (timelineBackTopBehavior.value === 'next' && !weakBacked) {
executeQueue(); executeQueue();
} }
}); });
@ -499,7 +498,7 @@ const prepend = (item: MisskeyEntity): void => {
// //
if (items.value.has(item.id)) return; // if (items.value.has(item.id)) return; //
unshiftItems([item]); unshiftItems([item]);
} else if (!isWebKit && !weakBacked) { } else if (timelineBackTopBehavior.value === 'next' && !weakBacked) {
// 調 // 調
prependQueue(item); prependQueue(item);
executeQueue(); executeQueue();
@ -538,7 +537,7 @@ function concatItems(oldItems: MisskeyEntity[]) {
async function executeQueue() { async function executeQueue() {
if (queue.value.size === 0) return; if (queue.value.size === 0) return;
if (isPausingUpdateByExecutingQueue.value) return; if (isPausingUpdateByExecutingQueue.value) return;
if (isWebKit) { if (timelineBackTopBehavior === 'newest') {
// Safari // Safari
const newItems = Array.from(queue.value.values()).slice(-1 * props.pagination.limit); const newItems = Array.from(queue.value.values()).slice(-1 * props.pagination.limit);
unshiftItems(newItems); unshiftItems(newItems);

View File

@ -21,10 +21,18 @@
</MkRadios> </MkRadios>
<FormSection> <FormSection>
<div class="_gaps_s"> <div class="_gaps_m">
<MkSwitch v-model="showFixedPostForm">{{ i18n.ts.showFixedPostForm }}</MkSwitch> <div class="_gaps_s">
<MkSwitch v-model="showFixedPostFormInChannel">{{ i18n.ts.showFixedPostFormInChannel }}</MkSwitch> <MkSwitch v-model="showFixedPostForm">{{ i18n.ts.showFixedPostForm }}</MkSwitch>
<MkSwitch v-model="showTimelineReplies">{{ i18n.ts.flagShowTimelineReplies }}<template #caption>{{ i18n.ts.flagShowTimelineRepliesDescription }} {{ i18n.ts.reflectMayTakeTime }}</template></MkSwitch> <MkSwitch v-model="showFixedPostFormInChannel">{{ i18n.ts.showFixedPostFormInChannel }}</MkSwitch>
<MkSwitch v-model="showTimelineReplies">{{ i18n.ts.flagShowTimelineReplies }}<template #caption>{{ i18n.ts.flagShowTimelineRepliesDescription }} {{ i18n.ts.reflectMayTakeTime }}</template></MkSwitch>
</div>
<MkSelect v-model="timelineBackTopBehavior" :disabled="isWebKit()">
<template #label>{{ i18n.ts.timelineBackTopBehavior }}</template>
<option value="newest">{{ i18n.ts._timelineBackTopBehavior.newest }}</option>
<option value="next">{{ i18n.ts._timelineBackTopBehavior.next }}</option>
</MkSelect>
</div> </div>
</FormSection> </FormSection>
@ -180,6 +188,7 @@ import { unisonReload } from '@/scripts/unison-reload';
import { i18n } from '@/i18n'; import { i18n } from '@/i18n';
import { definePageMetadata } from '@/scripts/page-metadata'; import { definePageMetadata } from '@/scripts/page-metadata';
import { miLocalStorage } from '@/local-storage'; import { miLocalStorage } from '@/local-storage';
import { isWebKit } from '@/scripts/useragent';
const lang = ref(miLocalStorage.getItem('lang')); const lang = ref(miLocalStorage.getItem('lang'));
const fontSize = ref(miLocalStorage.getItem('fontSize')); const fontSize = ref(miLocalStorage.getItem('fontSize'));
@ -226,6 +235,7 @@ const mediaListWithOneImageAppearance = computed(defaultStore.makeGetterSetter('
const notificationPosition = computed(defaultStore.makeGetterSetter('notificationPosition')); const notificationPosition = computed(defaultStore.makeGetterSetter('notificationPosition'));
const notificationStackAxis = computed(defaultStore.makeGetterSetter('notificationStackAxis')); const notificationStackAxis = computed(defaultStore.makeGetterSetter('notificationStackAxis'));
const showTimelineReplies = computed(defaultStore.makeGetterSetter('showTimelineReplies')); const showTimelineReplies = computed(defaultStore.makeGetterSetter('showTimelineReplies'));
const timelineBackTopBehavior = computed(defaultStore.makeGetterSetter('timelineBackTopBehavior'));
watch(lang, () => { watch(lang, () => {
miLocalStorage.setItem('lang', lang.value as string); miLocalStorage.setItem('lang', lang.value as string);

View File

@ -87,6 +87,7 @@ const defaultStoreSaveKeys: (keyof typeof defaultStore['state'])[] = [
'numberOfPageCache', 'numberOfPageCache',
'aiChanMode', 'aiChanMode',
'mediaListWithOneImageAppearance', 'mediaListWithOneImageAppearance',
'timelineBackTopBehavior',
]; ];
const coldDeviceStorageSaveKeys: (keyof typeof ColdDeviceStorage.default)[] = [ const coldDeviceStorageSaveKeys: (keyof typeof ColdDeviceStorage.default)[] = [
'lightTheme', 'lightTheme',

View File

@ -0,0 +1,3 @@
import { UAParser } from 'ua-parser-js';
const ua = new UAParser(navigator.userAgent);
export const isWebKit = () => ua.getEngine().name === 'WebKit';

View File

@ -1,5 +1,6 @@
import { markRaw, ref } from 'vue'; import { markRaw, ref } from 'vue';
import { Storage } from './pizzax'; import { Storage } from './pizzax';
import { isWebKit } from './scripts/useragent';
interface PostFormAction { interface PostFormAction {
title: string, title: string,
@ -342,6 +343,10 @@ export const defaultStore = markRaw(new Storage('base', {
where: 'device', where: 'device',
default: {} as Record<string, Record<string, string[]>>, default: {} as Record<string, Record<string, string[]>>,
}, },
timelineBackTopBehavior: {
where: 'device',
default: (isWebKit() ? 'newest' : 'next') as 'newest' | 'next',
},
})); }));
// TODO: 他のタブと永続化されたstateを同期 // TODO: 他のタブと永続化されたstateを同期