This commit is contained in:
tamaina 2023-07-11 14:14:15 +00:00
parent b4d532efb4
commit 035c98dc15
7 changed files with 63 additions and 38 deletions

2
locales/index.d.ts vendored
View File

@ -527,7 +527,7 @@ export interface Locale {
"deleteAll": string; "deleteAll": string;
"showFixedPostForm": string; "showFixedPostForm": string;
"showFixedPostFormInChannel": string; "showFixedPostFormInChannel": string;
"newNoteRecived": string; "goToTheHeadOfTimeline": string;
"sounds": string; "sounds": string;
"sound": string; "sound": string;
"listen": string; "listen": string;

View File

@ -524,7 +524,7 @@ serverLogs: "サーバーログ"
deleteAll: "全て削除" deleteAll: "全て削除"
showFixedPostForm: "タイムライン上部に投稿フォームを表示する" showFixedPostForm: "タイムライン上部に投稿フォームを表示する"
showFixedPostFormInChannel: "タイムライン上部に投稿フォームを表示する(チャンネル)" showFixedPostFormInChannel: "タイムライン上部に投稿フォームを表示する(チャンネル)"
newNoteRecived: "新しいノートがあります" goToTheHeadOfTimeline: "最新のノートに移動"
sounds: "サウンド" sounds: "サウンド"
sound: "サウンド" sound: "サウンド"
listen: "聴く" listen: "聴く"

View File

@ -8,7 +8,7 @@
> >
<MkLoading v-if="fetching"/> <MkLoading v-if="fetching"/>
<MkError v-else-if="error" @retry="init()"/> <MkError v-else-if="error" @retry="reload()"/>
<div v-else-if="empty" key="_empty_" class="empty"> <div v-else-if="empty" key="_empty_" class="empty">
<slot name="empty"> <slot name="empty">
@ -41,7 +41,7 @@
import { computed, ComputedRef, isRef, nextTick, onActivated, onBeforeUnmount, onDeactivated, onMounted, ref, watch } from 'vue'; import { computed, ComputedRef, isRef, nextTick, onActivated, onBeforeUnmount, onDeactivated, onMounted, ref, watch } from 'vue';
import * as misskey from 'misskey-js'; import * as misskey from 'misskey-js';
import * as os from '@/os'; 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 { useDocumentVisibility } from '@/scripts/use-document-visibility';
import MkButton from '@/components/MkButton.vue'; import MkButton from '@/components/MkButton.vue';
import { defaultStore } from '@/store'; import { defaultStore } from '@/store';
@ -125,7 +125,7 @@ const items = ref<MisskeyEntityMap>(new Map());
/** /**
* タブが非アクティブなどの場合に更新を貯めておく * タブが非アクティブなどの場合に更新を貯めておく
* 最新が0番目 * 最新が最後パフォーマンス上の理由でitemsと逆にした
*/ */
const queue = ref<MisskeyEntityMap>(new Map()); const queue = ref<MisskeyEntityMap>(new Map());
@ -231,15 +231,17 @@ watch([$$(weakBacked), $$(contentEl)], () => {
}); });
//#endregion //#endregion
if (props.pagination.params && isRef(props.pagination.params)) {
watch(props.pagination.params, init, { deep: true });
}
watch(queue, (a, b) => { watch(queue, (a, b) => {
if (a.size === 0 && b.size === 0) return; if (a.size === 0 && b.size === 0) return;
emit('queue', queue.value.size); emit('queue', queue.value.size);
}, { deep: true }); }, { deep: true });
/**
* 初期化
* scrollAfterInitなどの後処理もあるのでreload関数を使うべき
*
* 注意: moreFetchingをtrueにするのでfalseにする必要がある
*/
async function init(): Promise<void> { async function init(): Promise<void> {
items.value = new Map(); items.value = new Map();
queue.value = new Map(); queue.value = new Map();
@ -258,7 +260,7 @@ async function init(): Promise<void> {
concatItems(res); concatItems(res);
more.value = false; more.value = false;
} else { } else {
if (props.pagination.reversed) moreFetching.value = true; moreFetching.value = true;
concatItems(res); concatItems(res);
more.value = true; more.value = true;
} }
@ -272,10 +274,43 @@ async function init(): Promise<void> {
}); });
} }
const reload = (): Promise<void> => { /**
return init(); * initの後に呼ぶ
* コンポーネント作成直後でinitが呼ばれた時はonMountedで呼ばれる
* reloadでinitが呼ばれた時はreload内でinitの後に呼ばれる
*/
function scrollAfterInit() {
if (props.pagination.reversed) {
nextTick(() => {
setTimeout(() => {
if (contentEl) scrollToBottom(contentEl);
}, 200);
// scrollToBottommoreFetching
// more = true
setTimeout(() => {
moreFetching.value = false;
}, 2000);
});
} else {
nextTick(() => {
setTimeout(() => {
if (contentEl) scrollToTop(contentEl);
moreFetching.value = false;
}, 200);
});
}
}
const reload = async (): Promise<void> => {
await init();
scrollAfterInit();
}; };
if (props.pagination.params && isRef(props.pagination.params)) {
watch(props.pagination.params, reload, { deep: true });
}
const fetchMore = async (): Promise<void> => { const fetchMore = async (): Promise<void> => {
if (!more.value || fetching.value || moreFetching.value || items.value.size === 0) return; if (!more.value || fetching.value || moreFetching.value || items.value.size === 0) return;
moreFetching.value = true; moreFetching.value = true;
@ -472,12 +507,12 @@ function concatItems(oldItems: MisskeyEntity[]) {
function executeQueue() { function executeQueue() {
const queueArr = Array.from(queue.value.entries()); const queueArr = Array.from(queue.value.entries());
unshiftItems(queueArr.slice(-1 * props.pagination.limit).map(v => v[1])); unshiftItems(queueArr.slice(0, props.pagination.limit).map(v => v[1]).reverse());
queue.value = new Map(queueArr.slice(0, -1 * props.pagination.limit)); queue.value = new Map(queueArr.slice(props.pagination.limit));
} }
function prependQueue(newItem: MisskeyEntity) { 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 // nothing to do
}); });
function toBottom() {
scrollToBottom(contentEl!);
}
onMounted(() => { onMounted(() => {
inited.then(() => { inited.then(scrollAfterInit);
if (props.pagination.reversed) {
nextTick(() => {
setTimeout(toBottom, 800);
// scrollToBottommoreFetching
// more = true
setTimeout(() => {
moreFetching.value = false;
}, 2000);
});
}
});
}); });
onBeforeUnmount(() => { onBeforeUnmount(() => {

View File

@ -164,4 +164,10 @@ const timetravel = (date?: Date) => {
this.$refs.tl.reload(); this.$refs.tl.reload();
}; };
*/ */
defineExpose({
reload: () => {
tlComponent.pagingComponent?.reload();
},
});
</script> </script>

View File

@ -3,7 +3,7 @@
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
<MkSpacer :contentMax="800"> <MkSpacer :contentMax="800">
<div ref="rootEl" v-hotkey.global="keymap"> <div ref="rootEl" v-hotkey.global="keymap">
<div v-if="queue > 0" :class="$style.new"><button class="_buttonPrimary" :class="$style.newButton" @click="top()">{{ i18n.ts.newNoteRecived }}</button></div> <div v-if="queue > 0" :class="$style.new"><button class="_buttonPrimary" :class="$style.newButton" @click="top()">{{ i18n.ts.goToTheHeadOfTimeline }}</button></div>
<div :class="$style.tl"> <div :class="$style.tl">
<MkTimeline <MkTimeline
ref="tlEl" :key="antennaId" ref="tlEl" :key="antennaId"
@ -46,7 +46,7 @@ function queueUpdated(q) {
} }
function top() { function top() {
scroll(rootEl, { top: 0 }); tlEl?.reload();
} }
async function timetravel() { async function timetravel() {

View File

@ -6,7 +6,7 @@
<XTutorial v-if="$i && defaultStore.reactiveState.timelineTutorial.value != -1" class="_panel" style="margin-bottom: var(--margin);"/> <XTutorial v-if="$i && defaultStore.reactiveState.timelineTutorial.value != -1" class="_panel" style="margin-bottom: var(--margin);"/>
<MkPostForm v-if="defaultStore.reactiveState.showFixedPostForm.value" :class="$style.postForm" class="post-form _panel" fixed style="margin-bottom: var(--margin);"/> <MkPostForm v-if="defaultStore.reactiveState.showFixedPostForm.value" :class="$style.postForm" class="post-form _panel" fixed style="margin-bottom: var(--margin);"/>
<div v-if="queue > 0" :class="$style.new"><button class="_buttonPrimary" :class="$style.newButton" @click="top()">{{ i18n.ts.newNoteRecived }}</button></div> <div v-if="queue > 0" :class="$style.new"><button class="_buttonPrimary" :class="$style.newButton" @click="top()">{{ i18n.ts.goToTheHeadOfTimeline }}</button></div>
<div :class="$style.tl"> <div :class="$style.tl">
<MkTimeline <MkTimeline
ref="tlComponent" ref="tlComponent"
@ -58,7 +58,7 @@ function queueUpdated(q: number): void {
} }
function top(): void { function top(): void {
if (rootEl) scroll(rootEl, { top: 0 }); tlComponent?.reload();
} }
async function chooseList(ev: MouseEvent): Promise<void> { async function chooseList(ev: MouseEvent): Promise<void> {

View File

@ -3,7 +3,7 @@
<template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template> <template #header><MkPageHeader :actions="headerActions" :tabs="headerTabs"/></template>
<MkSpacer :contentMax="800"> <MkSpacer :contentMax="800">
<div ref="rootEl"> <div ref="rootEl">
<div v-if="queue > 0" :class="$style.new"><button class="_buttonPrimary" :class="$style.newButton" @click="top()">{{ i18n.ts.newNoteRecived }}</button></div> <div v-if="queue > 0" :class="$style.new"><button class="_buttonPrimary" :class="$style.newButton" @click="top()">{{ i18n.ts.goToTheHeadOfTimeline }}</button></div>
<div :class="$style.tl"> <div :class="$style.tl">
<MkTimeline <MkTimeline
ref="tlEl" :key="listId" ref="tlEl" :key="listId"
@ -49,7 +49,7 @@ function queueUpdated(q) {
} }
function top() { function top() {
scroll(rootEl, { top: 0 }); tlEl?.reload();
} }
function settings() { function settings() {