Compare commits

...

6 Commits

Author SHA1 Message Date
tamaina b05f2bb834 fix 2023-07-28 16:38:00 +00:00
tamaina 33c3583115 Merge branch 'pag-back' into noman 2023-07-28 15:58:11 +00:00
tamaina 7fc2309822 fix comment 2023-07-28 15:58:00 +00:00
tamaina d92fe0803c fix 2023-07-28 15:57:34 +00:00
tamaina 7e7aece2f5 ✌️ 2023-07-28 15:54:06 +00:00
tamaina 4e29da828f wip 2023-07-28 15:25:50 +00:00
4 changed files with 112 additions and 25 deletions

View File

@ -238,7 +238,16 @@ const translation = ref<any>(null);
const translating = ref(false);
const showTicker = (defaultStore.state.instanceTicker === 'always') || (defaultStore.state.instanceTicker === 'remote' && !!appearNote?.user.instance);
const canRenote = computed(() => (!!appearNote && !!$i) && (['public', 'home'].includes(appearNote.visibility) || appearNote.userId === $i.id));
let renoteCollapsed = $ref(note && appearNote && defaultStore.state.collapseRenotes && isRenote && (($i && ($i.id === note.userId || $i.id === appearNote.userId)) || (appearNote.myReaction != null)));
let renoteCollapsed = $ref(
note &&
appearNote &&
defaultStore.state.collapseRenotes &&
isRenote.value &&
(
($i && ($i.id === note.userId || $i.id === appearNote.userId)) ||
(appearNote.myReaction != null)
)
);
const keymap = {
'r': () => reply(true),
@ -518,12 +527,14 @@ onActivated(() => {
});
onDeactivated(() => {
if (unuse.value) {
unuse.value();
unuse.value = undefined;
}
//
setTimeout(() => {
if (unuse.value) {
unuse.value();
unuse.value = undefined;
}
}, 1000);
});
</script>
<style lang="scss" module>

View File

@ -87,6 +87,11 @@ export type Paging<E extends keyof misskey.Endpoints = keyof misskey.Endpoints>
offsetMode?: boolean;
pageEl?: HTMLElement;
/**
* 変換関数
*/
transform?: (source: Omit<MisskeyEntity, '_shouldInsertAd_'>[]) => MisskeyEntity[];
};
type MisskeyEntityMap = Map<string, MisskeyEntity>;
@ -169,6 +174,11 @@ const visibility = useDocumentVisibility();
const isPausingUpdateByExecutingQueue = ref(false);
const denyMoveTransition = ref(false);
/**
* 変換関数
*/
const transform = computed(() => props.pagination.transform ?? ((source: MisskeyEntity[]) => source));
//#region scrolling
const checkFn = props.pagination.reversed ? isBottomVisible : isTopVisible;
const checkTop = (tolerance?: number) => {
@ -298,7 +308,9 @@ async function init(): Promise<void> {
await os.api(props.pagination.endpoint, {
...params,
limit: props.pagination.limit ?? 10,
}).then(res => {
}).then(_res => {
const res = transform.value(_res);
for (let i = 0; i < res.length; i++) {
const item = res[i];
if (i === 3) item._shouldInsertAd_ = true;
@ -378,7 +390,9 @@ const fetchMore = async (): Promise<void> => {
} : {
untilId: Array.from(items.value.keys()).at(-1),
}),
}).then(res => {
}).then(_res => {
const res = transform.value(_res);
for (let i = 0; i < res.length; i++) {
const item = res[i];
if (i === 10) item._shouldInsertAd_ = true;
@ -425,15 +439,15 @@ const fetchMoreAhead = async (): Promise<void> => {
} : {
sinceId: Array.from(items.value.keys()).at(-1),
}),
}).then(res => {
if (res.length === 0) {
items.value = concatMapWithArray(items.value, res);
}).then(_res => {
if (_res.length === 0) {
more.value = false;
} else {
const res = transform.value(_res);
items.value = concatMapWithArray(items.value, res);
more.value = true;
}
offset.value += res.length;
offset.value += _res.length;
moreFetching.value = false;
}, err => {
moreFetching.value = false;
@ -484,9 +498,12 @@ watch([active, visibility], () => {
/**
* 最新のものとして1つだけアイテムを追加する
* ストリーミングから降ってきたアイテムはこれで追加する
* @param item アイテム
* @param item アイテムtransform前
*/
const prepend = (item: MisskeyEntity): void => {
const prepend = (_item: MisskeyEntity): void => {
const item = transform.value([_item])[0];
if (!item) return;
if (items.value.size === 0) {
items.value.set(item.id, item);
fetching.value = false;
@ -540,7 +557,10 @@ function concatItems(oldItems: MisskeyEntity[]) {
}
async function executeQueue() {
if (queue.value.size === 0) return;
//
//
// if (queue.value.size === 0) return;
if (isPausingUpdateByExecutingQueue.value) return;
if (timelineBackTopBehavior.value === 'newest') {
// Safari
@ -570,8 +590,12 @@ function prependQueue(newItem: MisskeyEntity) {
/*
* アイテムを末尾に追加する使うの
* @param item アイテムtransform前
*/
const appendItem = (item: MisskeyEntity): void => {
const appendItem = (_item: MisskeyEntity): void => {
const item = transform.value([_item])[0];
if (!item) return;
items.value.set(item.id, item);
};

View File

@ -26,6 +26,9 @@ import { $i } from '@/account';
import { defaultStore } from '@/store';
import { i18n } from '@/i18n';
import { instance } from '@/instance';
import { noteManager } from '@/scripts/entity-manager';
import { Note } from 'misskey-js/built/entities';
import { MisskeyEntity } from '@/types/date-separated-list';
const props = defineProps<{
src: string;
@ -62,6 +65,16 @@ const prepend = note => {
}
};
const transform = (notes: Note[]): MisskeyEntity[] => {
return notes.map(note => {
noteManager.set(note);
return {
id: note.id,
createdAt: note.createdAt,
};
});
};
let endpoint;
let query;
let connection;
@ -165,6 +178,7 @@ const pagination = {
endpoint: endpoint,
limit: 10,
params: query,
transform: transform,
};
onUnmounted(() => {

View File

@ -3,7 +3,7 @@
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { Note, UserLite } from "misskey-js/built/entities";
import { Note, UserLite, DriveFile } from "misskey-js/built/entities";
import { Ref, ref, ComputedRef, computed } from "vue";
import { api } from "./api";
import { useStream } from '@/stream';
@ -13,7 +13,9 @@ import { $i } from "@/account";
export class EntitiyManager<T extends { id: string }> {
private entities: Map<T['id'], Ref<T>>;
constructor() {
constructor(
public key: string,
) {
this.entities = new Map();
}
@ -32,7 +34,8 @@ export class EntitiyManager<T extends { id: string }> {
}
}
export const userLiteManager = new EntitiyManager<UserLite>();
export const userLiteManager = new EntitiyManager<UserLite>('userLite');
export const driveFileManager = new EntitiyManager<DriveFile>('driveFile');
type OmittedNote = Omit<Note, 'user' | 'renote' | 'reply'>;
type CachedNoteSource = Ref<OmittedNote | null>;
@ -53,8 +56,9 @@ export class NoteManager {
private notesSource: Map<Note['id'], CachedNoteSource>;
/**
* user, renote, replyを取得したComputedRef
* user, renote, replyを取得したComputedRefのキャッシュを保持しておく
* nullは削除済みであることを表す
* 0
*/
private notesComputed: Map<Note['id'], CachedNote>;
private updatedAt: Map<Note['id'], number>;
@ -67,7 +71,7 @@ export class NoteManager {
this.updatedAt = new Map();
this.captureing = new Map();
this.connection = $i ? useStream() : null;
this.connection?.on('noteUpdated', this.onStreamNoteUpdated);
this.connection?.on('noteUpdated', noteData => this.onStreamNoteUpdated(noteData));
this.connection?.on('_connected_', () => {
// 再接続時に再キャプチャ
for (const [id, captureingNumber] of Array.from(this.captureing)) {
@ -81,16 +85,29 @@ export class NoteManager {
});
}
public set(_note: Note): CachedNote {
public set(_note: Note): void {
const note: Note = { ..._note };
userLiteManager.set(note.user);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
//@ts-ignore
delete note.user;
if (note.fileIds.length > 0) {
for (const file of note.files) {
driveFileManager.set(file);
}
}
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
//@ts-ignore
delete note.files;
if (note.renote) this.set(note.renote);
delete note.renote;
if (note.reply) this.set(note.reply);
delete note.reply;
const cached = this.notesSource.get(note.id);
if (cached) {
cached.value = note;
@ -98,7 +115,6 @@ export class NoteManager {
this.notesSource.set(note.id, ref(note));
}
this.updatedAt.set(note.id, Date.now());
return this.get(note.id)!;
}
public get(id: string): CachedNote {
@ -117,11 +133,14 @@ export class NoteManager {
const reply = note.value.replyId ? this.get(note.value.replyId) : undefined;
if (reply && !reply.value) return null;
const files = note.value.fileIds.map(id => driveFileManager.get(id)?.value);
return {
...note.value,
user: user.value,
renote: renote?.value ?? undefined,
reply: reply?.value ?? undefined,
files: files.filter(file => file) as DriveFile[],
};
}));
}
@ -131,7 +150,8 @@ export class NoteManager {
public async fetch(id: string, force = false): Promise<CachedNote> {
if (!force) {
const updatedAt = this.updatedAt.get(id);
if (updatedAt && Date.now() - updatedAt < 1000 * 30) {
// 2分以上経過していない場合はキャッシュを返す
if (updatedAt && Date.now() - updatedAt < 1000 * 120) {
const cachedNote = this.get(id);
if (cachedNote) {
return cachedNote;
@ -139,7 +159,10 @@ export class NoteManager {
}
}
return api('notes/show', { noteId: id })
.then(fetchedNote => this.set(fetchedNote))
.then(fetchedNote => {
this.set(fetchedNote);
return this.get(id)!;
})
.catch(() => {
// エラーが発生した場合はとりあえず削除されたものとして扱う
const cached = this.notesSource.get(id);
@ -161,6 +184,8 @@ export class NoteManager {
if (!note || !note.value) {
this.connection?.send('un', { id });
this.captureing.delete(id);
this.notesComputed.delete(id);
this.updatedAt.delete(id);
return;
}
@ -219,6 +244,8 @@ export class NoteManager {
break;
}
}
this.updatedAt.set(id, Date.now());
}
private capture(id: string, markRead = true): void {
@ -252,6 +279,9 @@ export class NoteManager {
}
this.captureing.delete(id);
// キャプチャが終わったらcomputedキャッシュも消してしまう
this.notesComputed.delete(id);
}
/**
@ -287,3 +317,11 @@ export class NoteManager {
}
export const noteManager = new NoteManager();
if (_DEV_) {
console.log('entity manager initialized', {
noteManager,
userLiteManager,
driveFileManager,
});
}