diff --git a/locales/index.d.ts b/locales/index.d.ts index 8697b22e21..453465839f 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -527,7 +527,7 @@ export interface Locale { "deleteAll": string; "showFixedPostForm": string; "showFixedPostFormInChannel": string; - "newNoteRecived": string; + "goToTheHeadOfTimeline": string; "sounds": string; "sound": string; "listen": string; diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index 82efc8a469..2febef0a9e 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -524,7 +524,7 @@ serverLogs: "サーバーログ" deleteAll: "全て削除" showFixedPostForm: "タイムライン上部に投稿フォームを表示する" showFixedPostFormInChannel: "タイムライン上部に投稿フォームを表示する(チャンネル)" -newNoteRecived: "新しいノートがあります" +goToTheHeadOfTimeline: "最新のノートに移動" sounds: "サウンド" sound: "サウンド" listen: "聴く" diff --git a/packages/frontend/src/components/MkPagination.vue b/packages/frontend/src/components/MkPagination.vue index c91655138a..985b9a4973 100644 --- a/packages/frontend/src/components/MkPagination.vue +++ b/packages/frontend/src/components/MkPagination.vue @@ -8,7 +8,7 @@ > - +
@@ -41,7 +41,7 @@ import { computed, ComputedRef, isRef, nextTick, onActivated, onBeforeUnmount, onDeactivated, onMounted, ref, watch } from 'vue'; import * as misskey from 'misskey-js'; import * as os from '@/os'; -import { isBottomVisible, isTopVisible, getBodyScrollHeight, getScrollContainer, scrollToBottom, scroll } from '@/scripts/scroll'; +import { isBottomVisible, isTopVisible, getBodyScrollHeight, getScrollContainer, scrollToBottom, scroll, scrollToTop } from '@/scripts/scroll'; import { useDocumentVisibility } from '@/scripts/use-document-visibility'; import MkButton from '@/components/MkButton.vue'; import { defaultStore } from '@/store'; @@ -125,7 +125,7 @@ const items = ref(new Map()); /** * タブが非アクティブなどの場合に更新を貯めておく - * 最新が0番目 + * 最新が最後(パフォーマンス上の理由でitemsと逆にした) */ const queue = ref(new Map()); @@ -231,15 +231,17 @@ watch([$$(weakBacked), $$(contentEl)], () => { }); //#endregion -if (props.pagination.params && isRef(props.pagination.params)) { - watch(props.pagination.params, init, { deep: true }); -} - watch(queue, (a, b) => { if (a.size === 0 && b.size === 0) return; emit('queue', queue.value.size); }, { deep: true }); +/** + * 初期化 + * scrollAfterInitなどの後処理もあるので、reload関数を使うべき + * + * 注意: moreFetchingをtrueにするのでfalseにする必要がある + */ async function init(): Promise { items.value = new Map(); queue.value = new Map(); @@ -258,7 +260,7 @@ async function init(): Promise { concatItems(res); more.value = false; } else { - if (props.pagination.reversed) moreFetching.value = true; + moreFetching.value = true; concatItems(res); more.value = true; } @@ -272,10 +274,43 @@ async function init(): Promise { }); } -const reload = (): Promise => { - return init(); +/** + * initの後に呼ぶ + * コンポーネント作成直後でinitが呼ばれた時はonMountedで呼ばれる + * reloadでinitが呼ばれた時はreload内でinitの後に呼ばれる + */ +function scrollAfterInit() { + if (props.pagination.reversed) { + nextTick(() => { + setTimeout(() => { + if (contentEl) scrollToBottom(contentEl); + }, 200); + + // scrollToBottomでmoreFetchingボタンが画面外まで出るまで + // more = trueを遅らせる + setTimeout(() => { + moreFetching.value = false; + }, 2000); + }); + } else { + nextTick(() => { + setTimeout(() => { + if (contentEl) scrollToTop(contentEl); + moreFetching.value = false; + }, 200); + }); + } +} + +const reload = async (): Promise => { + await init(); + scrollAfterInit(); }; +if (props.pagination.params && isRef(props.pagination.params)) { + watch(props.pagination.params, reload, { deep: true }); +} + const fetchMore = async (): Promise => { if (!more.value || fetching.value || moreFetching.value || items.value.size === 0) return; moreFetching.value = true; @@ -472,12 +507,12 @@ function concatItems(oldItems: MisskeyEntity[]) { function executeQueue() { const queueArr = Array.from(queue.value.entries()); - unshiftItems(queueArr.slice(-1 * props.pagination.limit).map(v => v[1])); - queue.value = new Map(queueArr.slice(0, -1 * props.pagination.limit)); + unshiftItems(queueArr.slice(0, props.pagination.limit).map(v => v[1]).reverse()); + queue.value = new Map(queueArr.slice(props.pagination.limit)); } function prependQueue(newItem: MisskeyEntity) { - queue.value = new Map([[newItem.id, newItem], ...queue.value] as [string, MisskeyEntity][]); + queue.value.set(newItem.id, newItem); } /* @@ -510,24 +545,8 @@ onDeactivated(() => { // nothing to do }); -function toBottom() { - scrollToBottom(contentEl!); -} - onMounted(() => { - inited.then(() => { - if (props.pagination.reversed) { - nextTick(() => { - setTimeout(toBottom, 800); - - // scrollToBottomでmoreFetchingボタンが画面外まで出るまで - // more = trueを遅らせる - setTimeout(() => { - moreFetching.value = false; - }, 2000); - }); - } - }); + inited.then(scrollAfterInit); }); onBeforeUnmount(() => { diff --git a/packages/frontend/src/components/MkTimeline.vue b/packages/frontend/src/components/MkTimeline.vue index 2595ebc45d..13d5b9f88d 100644 --- a/packages/frontend/src/components/MkTimeline.vue +++ b/packages/frontend/src/components/MkTimeline.vue @@ -164,4 +164,10 @@ const timetravel = (date?: Date) => { this.$refs.tl.reload(); }; */ + +defineExpose({ + reload: () => { + tlComponent.pagingComponent?.reload(); + }, +}); diff --git a/packages/frontend/src/pages/antenna-timeline.vue b/packages/frontend/src/pages/antenna-timeline.vue index a22714791f..b2bc889cfb 100644 --- a/packages/frontend/src/pages/antenna-timeline.vue +++ b/packages/frontend/src/pages/antenna-timeline.vue @@ -3,7 +3,7 @@
-
+
-
+
{ diff --git a/packages/frontend/src/pages/user-list-timeline.vue b/packages/frontend/src/pages/user-list-timeline.vue index f66670e1f6..67a576ce83 100644 --- a/packages/frontend/src/pages/user-list-timeline.vue +++ b/packages/frontend/src/pages/user-list-timeline.vue @@ -3,7 +3,7 @@
-
+