insertNewNotes

This commit is contained in:
fly_mc 2024-11-10 21:20:44 +08:00
parent 5813b499b4
commit 76a69d3a6b
7 changed files with 83 additions and 15 deletions

View file

@ -63,7 +63,7 @@ copyFileId: "Copy file ID"
copyFolderId: "Copy folder ID"
copyProfileUrl: "Copy profile URL"
searchUser: "Search for a user"
searchThisUsersNotes: "Search this users notes"
searchThisUsersNotes: "Search this user's notes"
reply: "Reply"
loadMore: "Load more"
showMore: "Show more"
@ -856,7 +856,7 @@ administration: "Management"
accounts: "Accounts"
switch: "Switch"
noMaintainerInformationWarning: "Maintainer information is not configured."
noInquiryUrlWarning: "Inquiry URL isnt set"
noInquiryUrlWarning: "Inquiry URL isn't set"
noBotProtectionWarning: "Bot protection is not configured."
configure: "Configure"
postToGallery: "Create new gallery post"
@ -2796,7 +2796,7 @@ _urlPreviewSetting:
title: "URL preview settings"
enable: "Enable URL preview"
timeout: "Time out when getting preview (ms)"
timeoutDescription: "If it takes longer than this value to get the preview, the preview wont be generated."
timeoutDescription: "If it takes longer than this value to get the preview, the preview won't be generated."
maximumContentLength: "Maximum Content-Length (bytes)"
maximumContentLengthDescription: "If Content-Length is higher than this value, the preview won't be generated."
requireContentLength: "Generate the preview only if you could get Content-Length"
@ -2829,9 +2829,11 @@ _embedCodeGen:
generateCode: "Generate embed code"
codeGenerated: "The code has been generated"
codeGeneratedDescription: "Paste the generated code into your website to embed the content."
_selfXssPrevention:
_selfXssPrevention:
warning: "WARNING"
title: "Any request to 'paste something into this screen' is a scam."
description1: "Pasting content here could allow malicious users to hijack your account or steal your personal information."
description2: "If you don't fully understand what you're about to paste, %cplease stop immediately and close this window."
description3: "For more information, please check here: {link}"
insertNewNotes: "Insert new notes at current position"
insertNewNotesDescription: "When receiving new notes while scrolling timeline, insert them at current viewing position. If disabled, show notification as usual."

View file

@ -147,7 +147,7 @@ renoteMute: "リノートをミュート"
renoteUnmute: "リノートのミュートを解除"
block: "ブロック"
unblock: "ブロック解除"
suspend: "凍"
suspend: "凍<EFBFBD><EFBFBD>"
unsuspend: "解凍"
blockConfirm: "ブロックしますか?"
unblockConfirm: "ブロック解除しますか?"
@ -454,7 +454,7 @@ totpDescription: "認証アプリを使ってワンタイムパスワードを
moderator: "モデレーター"
moderation: "モデレーション"
moderationNote: "モデレーションノート"
moderationNoteDescription: "モレーター間でだけ共有されるメモを記入することができます。"
moderationNoteDescription: "モ<EFBFBD><EFBFBD>レーター間でだけ共有されるメモを記入することができます。"
addModerationNote: "モデレーションノートを追加する"
moderationLogs: "モデログ"
nUsersMentioned: "{n}人が投稿"
@ -537,7 +537,7 @@ fontSize: "フォントサイズ"
mediaListWithOneImageAppearance: "画像が1枚のみのメディアリストの高さ"
limitTo: "{x}を上限に"
noFollowRequests: "フォロー申請はありません"
openImageInNewTab: "画像新しいタブで開く"
openImageInNewTab: "画像<EFBFBD><EFBFBD>新しいタブで開く"
dashboard: "ダッシュボード"
local: "ローカル"
remote: "リモート"
@ -681,7 +681,7 @@ smtpUser: "ユーザー名"
smtpPass: "パスワード"
emptyToDisableSmtpAuth: "ユーザー名とパスワードを空欄にすることで、SMTP認証を無効化出来ます"
smtpSecure: "SMTP 接続に暗黙的なSSL/TLSを使用する"
smtpSecureInfo: "STARTTLS使用時はオフにます。"
smtpSecureInfo: "STARTTLS使用時はオフに<EFBFBD><EFBFBD><EFBFBD>ます。"
testEmail: "配信テスト"
wordMute: "ワードミュート"
hardWordMute: "ハードワードミュート"
@ -1052,7 +1052,7 @@ thisPostMayBeAnnoyingCancel: "やめる"
thisPostMayBeAnnoyingIgnore: "このまま投稿"
collapseRenotes: "リノートのスマート省略"
collapseRenotesDescription: "リアクションやリノートをしたことがあるノートをたたんで表示します。"
internalServerError: "サーバー部エラー"
internalServerError: "サーバー<EFBFBD><EFBFBD><EFBFBD>部エラー"
internalServerErrorDescription: "サーバー内部で予期しないエラーが発生しました。"
copyErrorInfo: "エラー情報をコピー"
joinThisServer: "このサーバーに登録する"
@ -1228,7 +1228,7 @@ detachAll: "全て外す"
angle: "角度"
flip: "反転"
showAvatarDecorations: "アイコンのデコレーションを表示"
releaseToRefresh: "離してロード"
releaseToRefresh: "離して<EFBFBD><EFBFBD>ロード"
refreshing: "リロード中"
pullDownToRefresh: "引っ張ってリロード"
disableStreamingTimeline: "タイムラインのリアルタイム更新を無効にする"
@ -1366,7 +1366,7 @@ _announcement:
_initialAccountSetting:
accountCreated: "アカウントの作成が完了しました!"
letsStartAccountSetup: "さっそくアカウントの初期設定を行いましょう。"
letsFillYourProfile: "まずはあなたのプロフィールを設定しましう。"
letsFillYourProfile: "まずはあなたのプロフィールを設定しまし<EFBFBD><EFBFBD><EFBFBD>う。"
profileSetting: "プロフィール設定"
privacySetting: "プライバシー設定"
theseSettingsCanEditLater: "これらの設定は後から変更できます。"
@ -1517,7 +1517,7 @@ _achievements:
title: "ノートノートノート"
description: "ートを30,000回投稿した"
_notes40000:
title: "ノート工"
title: "ノート工<EFBFBD><EFBFBD><EFBFBD>"
description: "ートを40,000回投稿した"
_notes50000:
title: "ノートの惑星"
@ -2011,7 +2011,7 @@ _theme:
darken: "暗さ"
lighten: "明るさ"
inputConstantName: "定数名を入力してください"
importInfo: "ここにテーマードを貼り付けて、エディターにインポートできます"
importInfo: "ここにテーマ<EFBFBD><EFBFBD>ードを貼り付けて、エディターにインポートできます"
deleteConstantConfirm: "定数 {const} を削除しても良いですか?"
keys:
@ -2221,7 +2221,7 @@ _auth:
permissionAsk: "このアプリは次の権限を要求しています"
pleaseGoBack: "アプリケーションに戻ってやっていってください"
callback: "アプリケーションに戻っています"
accepted: "アクスを許可しました"
accepted: "アク<EFBFBD><EFBFBD>スを許可しました"
denied: "アクセスを拒否しました"
scopeUser: "以下のユーザーとして操作しています"
pleaseLogin: "アプリケーションにアクセス許可を与えるには、ログインが必要です。"
@ -2821,3 +2821,6 @@ _selfXssPrevention:
description1: "ここに何かを貼り付けると、悪意のあるユーザーにアカウントを乗っ取られたり、個人情報を盗まれたりする可能性があります。"
description2: "貼り付けようとしているものが何なのかを正確に理解していない場合は、%c今すぐ作業を中止してこのウィンドウを閉じてください。"
description3: "詳しくはこちらをご確認ください。 {link}"
insertNewNotes: "新着ノートを表示位置に挿入"
insertNewNotesDescription: "タイムラインをスクロール中に新着ノートを受信した場合、現在の表示位置に挿入します。オフの場合は従来通り通知を表示します。"

View file

@ -9,6 +9,7 @@ SPDX-License-Identifier: AGPL-3.0-only
v-show="!isDeleted"
ref="rootEl"
v-hotkey="keymap"
:data-note-id="note.id"
:class="[$style.root, { [$style.showActionsOnlyHover]: defaultStore.state.showNoteActionsOnlyHover, [$style.skipRender]: defaultStore.state.skipNoteRender || defaultStore.state.enableRenderingOptimization }]"
:tabindex="isDeleted ? '-1' : '0'"
>

View file

@ -478,6 +478,54 @@ onBeforeUnmount(() => {
scrollObserver.value?.disconnect();
});
//
const insertNote = (item: MisskeyEntity): void => {
if (items.value.size === 0) {
items.value.set(item.id, item);
fetching.value = false;
return;
}
// ,
if (isTop() && !isPausingUpdate) {
unshiftItems([item]);
} else {
// ,
if (defaultStore.state.insertNewNotes) {
//
const entries = Array.from(items.value.entries());
const visibleIndex = findFirstVisibleNoteIndex(entries);
if (visibleIndex !== -1) {
entries.splice(visibleIndex, 0, [item.id, item]);
items.value = new Map(entries);
} else {
// ,
prependQueue(item);
}
} else {
//
prependQueue(item);
}
}
};
//
function findFirstVisibleNoteIndex(entries: [string, MisskeyEntity][]): number {
if (!rootEl.value) return -1;
const notes = rootEl.value.querySelectorAll('[data-note-id]');
for (let i = 0; i < notes.length; i++) {
const note = notes[i];
const rect = note.getBoundingClientRect();
if (rect.top >= 0 && rect.bottom <= window.innerHeight) {
// entry index
const noteId = note.getAttribute('data-note-id');
return entries.findIndex(([id]) => id === noteId);
}
}
return -1;
}
defineExpose({
items,
queue,
@ -488,6 +536,7 @@ defineExpose({
append: appendItem,
removeItem,
updateItem,
insertNote,
});
</script>

View file

@ -82,7 +82,11 @@ function prepend(note) {
note._shouldInsertAd_ = true;
}
tlComponent.value.pagingComponent?.prepend(note);
if (defaultStore.state.insertNewNotes) {
tlComponent.value.pagingComponent?.insertNote(note);
} else {
tlComponent.value.pagingComponent?.prepend(note);
}
emit('note');

View file

@ -75,6 +75,10 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkSwitch v-model="disableReactionsViewer">{{ i18n.ts.disableReactionsViewer }}</MkSwitch>
<MkSwitch v-model="collapsedUnexpectedLangs">{{ i18n.ts.collapsedUnexpectedLangs }}</MkSwitch>
<MkSwitch v-model="emojiAutoSpacing">{{ i18n.ts.emojiAutoSpacing }}</MkSwitch>
<MkSwitch v-model="insertNewNotes">
<template #label>{{ i18n.ts.insertNewNotes }}</template>
<template #caption>{{ i18n.ts.insertNewNotesDescription }}</template>
</MkSwitch>
<MkSelect v-model="autoSpacingBehaviour">
<template #label>{{ i18n.ts.autoSpacing }}</template>
<option :value="null">{{ i18n.ts.disabled }}</option>
@ -132,6 +136,7 @@ const collapseNotesRepliedTo = computed(defaultStore.makeGetterSetter('collapseN
const disableReactionsViewer = computed(defaultStore.makeGetterSetter('disableReactionsViewer'));
const collapsedUnexpectedLangs = computed(defaultStore.makeGetterSetter('collapsedUnexpectedLangs'));
const emojiAutoSpacing = computed(defaultStore.makeGetterSetter('emojiAutoSpacing'));
const insertNewNotes = computed(defaultStore.makeGetterSetter('insertNewNotes'));
definePageMetadata(() => ({
title: 'Pari Plus!',

View file

@ -559,6 +559,10 @@ export const defaultStore = markRaw(new Storage('base', {
where: 'device',
default: true,
},
insertNewNotes: {
where: 'device',
default: false,
},
}));
// TODO: 他のタブと永続化されたstateを同期