From cc8d60e53b608778abed1151b0f3ffa9acac93fb Mon Sep 17 00:00:00 2001
From: YS <47836716+yszkst@users.noreply.github.com>
Date: Sat, 25 Feb 2023 08:18:12 +0900
Subject: [PATCH] =?UTF-8?q?=E3=83=90=E3=83=83=E3=82=AF=E3=82=B0=E3=83=A9?=
 =?UTF-8?q?=E3=82=A6=E3=83=B3=E3=83=89=E3=81=A7=E4=B8=80=E5=AE=9A=E6=99=82?=
 =?UTF-8?q?=E9=96=93=E7=B5=8C=E9=81=8E=E3=81=97=E3=81=9F=E3=82=89=E3=83=9A?=
 =?UTF-8?q?=E3=83=BC=E3=82=B8=E3=83=8D=E3=83=BC=E3=82=B7=E3=83=A7=E3=83=B3?=
 =?UTF-8?q?=E3=81=AE=E3=82=A2=E3=82=A4=E3=83=86=E3=83=A0=E6=9B=B4=E6=96=B0?=
 =?UTF-8?q?=E3=82=92=E3=81=97=E3=81=AA=E3=81=84=20(#10053)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../frontend/src/components/MkPagination.vue  | 37 +++++++++++++++++--
 .../src/scripts/use-document-visibility.ts    | 19 ++++++++++
 2 files changed, 53 insertions(+), 3 deletions(-)
 create mode 100644 packages/frontend/src/scripts/use-document-visibility.ts

diff --git a/packages/frontend/src/components/MkPagination.vue b/packages/frontend/src/components/MkPagination.vue
index 84ba94361e..378d0ac020 100644
--- a/packages/frontend/src/components/MkPagination.vue
+++ b/packages/frontend/src/components/MkPagination.vue
@@ -42,6 +42,7 @@ import { computed, ComputedRef, isRef, nextTick, onActivated, onBeforeUnmount, o
 import * as misskey from 'misskey-js';
 import * as os from '@/os';
 import { onScrollTop, isTopVisible, getBodyScrollHeight, getScrollContainer, onScrollBottom, scrollToBottom, scroll, isBottomVisible } from '@/scripts/scroll';
+import { useDocumentVisibility } from '@/scripts/use-document-visibility';
 import MkButton from '@/components/MkButton.vue';
 import { defaultStore } from '@/store';
 import { MisskeyEntity } from '@/types/date-separated-list';
@@ -107,6 +108,12 @@ const {
 const contentEl = $computed(() => props.pagination.pageEl ?? rootEl);
 const scrollableElement = $computed(() => getScrollContainer(contentEl));
 
+const visibility = useDocumentVisibility();
+
+let isPausingUpdate = false;
+let timerForSetPause: number | null = null;
+const BACKGROUND_PAUSE_WAIT_SEC = 10;
+
 // 先頭が表示されているかどうかを検出
 // https://qiita.com/mkataigi/items/0154aefd2223ce23398e
 let scrollObserver = $ref<IntersectionObserver>();
@@ -279,6 +286,28 @@ const fetchMoreAhead = async (): Promise<void> => {
 	});
 };
 
+const isTop = (): boolean => isBackTop.value || (props.pagination.reversed ? isBottomVisible : isTopVisible)(contentEl, TOLERANCE);
+
+watch(visibility, () => {
+	if (visibility.value === 'hidden') {
+		timerForSetPause = window.setTimeout(() => {
+			isPausingUpdate = true;
+			timerForSetPause = null;
+		},
+		BACKGROUND_PAUSE_WAIT_SEC * 1000);
+	} else { // 'visible'
+		if (timerForSetPause) {
+			clearTimeout(timerForSetPause);
+			timerForSetPause = null;
+		} else {
+			isPausingUpdate = false;
+			if (isTop()) {
+				executeQueue();
+			}
+		}
+	}
+});
+
 const prepend = (item: MisskeyEntity): void => {
 	// 初回表示時はunshiftだけでOK
 	if (!rootEl) {
@@ -286,9 +315,7 @@ const prepend = (item: MisskeyEntity): void => {
 		return;
 	}
 
-	const isTop = isBackTop.value || (props.pagination.reversed ? isBottomVisible : isTopVisible)(contentEl, TOLERANCE);
-
-	if (isTop) unshiftItems([item]);
+	if (isTop() && !isPausingUpdate) unshiftItems([item]);
 	else prependQueue(item);
 };
 
@@ -357,6 +384,10 @@ onMounted(() => {
 });
 
 onBeforeUnmount(() => {
+	if (timerForSetPause) {
+		clearTimeout(timerForSetPause);
+		timerForSetPause = null;
+	}
 	scrollObserver.disconnect();
 });
 
diff --git a/packages/frontend/src/scripts/use-document-visibility.ts b/packages/frontend/src/scripts/use-document-visibility.ts
new file mode 100644
index 0000000000..47e91dd937
--- /dev/null
+++ b/packages/frontend/src/scripts/use-document-visibility.ts
@@ -0,0 +1,19 @@
+import { onMounted, onUnmounted, ref, Ref } from 'vue';
+
+export function useDocumentVisibility(): Ref<DocumentVisibilityState> {
+	const visibility = ref(document.visibilityState);
+
+	const onChange = (): void => {
+		visibility.value = document.visibilityState;
+	};
+
+	onMounted(() => {
+		document.addEventListener('visibilitychange', onChange);
+	});
+
+	onUnmounted(() => {
+		document.removeEventListener('visibilitychange', onChange);
+	});
+
+	return visibility;
+}