add "show bots" toggle to following feed
This commit is contained in:
parent
24fd35e03d
commit
9b1bae653d
6 changed files with 35 additions and 7 deletions
|
@ -37,6 +37,7 @@ export const paramDef = {
|
||||||
includeNonPublic: { type: 'boolean', default: false },
|
includeNonPublic: { type: 'boolean', default: false },
|
||||||
includeReplies: { type: 'boolean', default: false },
|
includeReplies: { type: 'boolean', default: false },
|
||||||
includeQuotes: { type: 'boolean', default: false },
|
includeQuotes: { type: 'boolean', default: false },
|
||||||
|
includeBots: { type: 'boolean', default: true },
|
||||||
|
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
sinceId: { type: 'string', format: 'misskey:id' },
|
sinceId: { type: 'string', format: 'misskey:id' },
|
||||||
|
@ -97,6 +98,11 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
query.andWhere('latest.is_quote = false');
|
query.andWhere('latest.is_quote = false');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Match selected user types.
|
||||||
|
if (!ps.includeBots) {
|
||||||
|
query.andWhere('"user"."isBot" = false');
|
||||||
|
}
|
||||||
|
|
||||||
// Respect blocks and mutes
|
// Respect blocks and mutes
|
||||||
this.queryService.generateBlockedUserQuery(query, me);
|
this.queryService.generateBlockedUserQuery(query, me);
|
||||||
this.queryService.generateMutedUserQuery(query, me);
|
this.queryService.generateMutedUserQuery(query, me);
|
||||||
|
|
|
@ -55,6 +55,7 @@ export const paramDef = {
|
||||||
withRepliesToSelf: { type: 'boolean', default: true },
|
withRepliesToSelf: { type: 'boolean', default: true },
|
||||||
withQuotes: { type: 'boolean', default: true },
|
withQuotes: { type: 'boolean', default: true },
|
||||||
withRenotes: { type: 'boolean', default: true },
|
withRenotes: { type: 'boolean', default: true },
|
||||||
|
withBots: { type: 'boolean', default: true },
|
||||||
withNonPublic: { type: 'boolean', default: true },
|
withNonPublic: { type: 'boolean', default: true },
|
||||||
withChannelNotes: { type: 'boolean', default: false },
|
withChannelNotes: { type: 'boolean', default: false },
|
||||||
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
limit: { type: 'integer', minimum: 1, maximum: 100, default: 10 },
|
||||||
|
@ -108,6 +109,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
withFiles: ps.withFiles,
|
withFiles: ps.withFiles,
|
||||||
withRenotes: ps.withRenotes,
|
withRenotes: ps.withRenotes,
|
||||||
withQuotes: ps.withQuotes,
|
withQuotes: ps.withQuotes,
|
||||||
|
withBots: ps.withBots,
|
||||||
withNonPublic: ps.withNonPublic,
|
withNonPublic: ps.withNonPublic,
|
||||||
withRepliesToOthers: ps.withReplies,
|
withRepliesToOthers: ps.withReplies,
|
||||||
withRepliesToSelf: ps.withRepliesToSelf,
|
withRepliesToSelf: ps.withRepliesToSelf,
|
||||||
|
@ -135,6 +137,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
excludeReplies: ps.withChannelNotes && !ps.withReplies, // userTimelineWithChannel may include replies
|
excludeReplies: ps.withChannelNotes && !ps.withReplies, // userTimelineWithChannel may include replies
|
||||||
excludeNoFiles: ps.withChannelNotes && ps.withFiles, // userTimelineWithChannel may include notes without files
|
excludeNoFiles: ps.withChannelNotes && ps.withFiles, // userTimelineWithChannel may include notes without files
|
||||||
excludePureRenotes: !ps.withRenotes,
|
excludePureRenotes: !ps.withRenotes,
|
||||||
|
excludeBots: !ps.withBots,
|
||||||
noteFilter: note => {
|
noteFilter: note => {
|
||||||
if (note.channel?.isSensitive && !isSelf) return false;
|
if (note.channel?.isSensitive && !isSelf) return false;
|
||||||
if (note.visibility === 'specified' && (!me || (me.id !== note.userId && !note.visibleUserIds.some(v => v === me.id)))) return false;
|
if (note.visibility === 'specified' && (!me || (me.id !== note.userId && !note.visibleUserIds.some(v => v === me.id)))) return false;
|
||||||
|
@ -156,6 +159,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
withFiles: ps.withFiles,
|
withFiles: ps.withFiles,
|
||||||
withRenotes: ps.withRenotes,
|
withRenotes: ps.withRenotes,
|
||||||
withQuotes: ps.withQuotes,
|
withQuotes: ps.withQuotes,
|
||||||
|
withBots: ps.withBots,
|
||||||
withNonPublic: ps.withNonPublic,
|
withNonPublic: ps.withNonPublic,
|
||||||
withRepliesToOthers: ps.withReplies,
|
withRepliesToOthers: ps.withReplies,
|
||||||
withRepliesToSelf: ps.withRepliesToSelf,
|
withRepliesToSelf: ps.withRepliesToSelf,
|
||||||
|
@ -175,6 +179,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
withFiles: boolean,
|
withFiles: boolean,
|
||||||
withRenotes: boolean,
|
withRenotes: boolean,
|
||||||
withQuotes: boolean,
|
withQuotes: boolean,
|
||||||
|
withBots: boolean,
|
||||||
withNonPublic: boolean,
|
withNonPublic: boolean,
|
||||||
withRepliesToOthers: boolean,
|
withRepliesToOthers: boolean,
|
||||||
withRepliesToSelf: boolean,
|
withRepliesToSelf: boolean,
|
||||||
|
@ -246,6 +251,10 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
|
||||||
query.andWhere('note.visibility = \'public\'');
|
query.andWhere('note.visibility = \'public\'');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!ps.withBots) {
|
||||||
|
query.andWhere('"user"."isBot" = false');
|
||||||
|
}
|
||||||
|
|
||||||
return await query.limit(ps.limit).getMany();
|
return await query.limit(ps.limit).getMany();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ const props = defineProps<{
|
||||||
withNonPublic: boolean;
|
withNonPublic: boolean;
|
||||||
withQuotes: boolean;
|
withQuotes: boolean;
|
||||||
withReplies: boolean;
|
withReplies: boolean;
|
||||||
|
withBots: boolean;
|
||||||
onlyFiles: boolean;
|
onlyFiles: boolean;
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
|
|
|
@ -30,18 +30,12 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
<div v-if="isWideViewport" ref="userScroll" :class="$style.user">
|
<div v-if="isWideViewport" ref="userScroll" :class="$style.user">
|
||||||
<MkHorizontalSwipe v-if="selectedUserId" v-model:tab="currentTab" :tabs="headerTabs">
|
<MkHorizontalSwipe v-if="selectedUserId" v-model:tab="currentTab" :tabs="headerTabs">
|
||||||
<SkUserRecentNotes ref="userRecentNotes" :userId="selectedUserId" :withNonPublic="withNonPublic" :withQuotes="withQuotes" :withReplies="withReplies" :onlyFiles="onlyFiles"/>
|
<SkUserRecentNotes ref="userRecentNotes" :userId="selectedUserId" :withNonPublic="withNonPublic" :withQuotes="withQuotes" :withBots="withBots" :withReplies="withReplies" :onlyFiles="onlyFiles"/>
|
||||||
</MkHorizontalSwipe>
|
</MkHorizontalSwipe>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
|
||||||
export type FollowingFeedTab = typeof followingTab | typeof mutualsTab;
|
|
||||||
export const followingTab = 'following' as const;
|
|
||||||
export const mutualsTab = 'mutuals' as const;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, Ref, ref, shallowRef } from 'vue';
|
import { computed, Ref, ref, shallowRef } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
|
@ -74,6 +68,10 @@ const withQuotes = computed({
|
||||||
get: () => defaultStore.reactiveState.followingFeed.value.withQuotes,
|
get: () => defaultStore.reactiveState.followingFeed.value.withQuotes,
|
||||||
set: value => saveFollowingFilter('withQuotes', value),
|
set: value => saveFollowingFilter('withQuotes', value),
|
||||||
});
|
});
|
||||||
|
const withBots = computed({
|
||||||
|
get: () => defaultStore.reactiveState.followingFeed.value.withBots,
|
||||||
|
set: value => saveFollowingFilter('withBots', value),
|
||||||
|
});
|
||||||
const withReplies = computed({
|
const withReplies = computed({
|
||||||
get: () => defaultStore.reactiveState.followingFeed.value.withReplies,
|
get: () => defaultStore.reactiveState.followingFeed.value.withReplies,
|
||||||
set: value => saveFollowingFilter('withReplies', value),
|
set: value => saveFollowingFilter('withReplies', value),
|
||||||
|
@ -95,10 +93,13 @@ function saveFollowingFilter(key: keyof typeof defaultStore.state.followingFeed,
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
const followingTab = 'following' as const;
|
||||||
|
const mutualsTab = 'mutuals' as const;
|
||||||
const currentTab = computed({
|
const currentTab = computed({
|
||||||
get: () => onlyMutuals.value ? mutualsTab : followingTab,
|
get: () => onlyMutuals.value ? mutualsTab : followingTab,
|
||||||
set: value => onlyMutuals.value = (value === mutualsTab),
|
set: value => onlyMutuals.value = (value === mutualsTab),
|
||||||
});
|
});
|
||||||
|
|
||||||
const userRecentNotes = shallowRef<InstanceType<typeof SkUserRecentNotes>>();
|
const userRecentNotes = shallowRef<InstanceType<typeof SkUserRecentNotes>>();
|
||||||
const userScroll = shallowRef<HTMLElement>();
|
const userScroll = shallowRef<HTMLElement>();
|
||||||
const noteScroll = shallowRef<HTMLElement>();
|
const noteScroll = shallowRef<HTMLElement>();
|
||||||
|
@ -188,6 +189,7 @@ const latestNotesPagination: Paging<'notes/following'> = {
|
||||||
includeNonPublic: withNonPublic.value,
|
includeNonPublic: withNonPublic.value,
|
||||||
includeReplies: withReplies.value,
|
includeReplies: withReplies.value,
|
||||||
includeQuotes: withQuotes.value,
|
includeQuotes: withQuotes.value,
|
||||||
|
includeBots: withBots.value,
|
||||||
})),
|
})),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -212,6 +214,11 @@ const headerActions: PageHeaderItem[] = [
|
||||||
text: i18n.ts.showQuotes,
|
text: i18n.ts.showQuotes,
|
||||||
ref: withQuotes,
|
ref: withQuotes,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
type: 'switch',
|
||||||
|
text: i18n.ts.showBots,
|
||||||
|
ref: withBots,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
type: 'switch',
|
type: 'switch',
|
||||||
text: i18n.ts.showReplies,
|
text: i18n.ts.showReplies,
|
||||||
|
|
|
@ -244,6 +244,7 @@ export const defaultStore = markRaw(new Storage('base', {
|
||||||
default: {
|
default: {
|
||||||
withNonPublic: false,
|
withNonPublic: false,
|
||||||
withQuotes: false,
|
withQuotes: false,
|
||||||
|
withBots: true,
|
||||||
withReplies: false,
|
withReplies: false,
|
||||||
onlyFiles: false,
|
onlyFiles: false,
|
||||||
onlyMutuals: false,
|
onlyMutuals: false,
|
||||||
|
|
|
@ -22304,6 +22304,8 @@ export type operations = {
|
||||||
includeReplies?: boolean;
|
includeReplies?: boolean;
|
||||||
/** @default false */
|
/** @default false */
|
||||||
includeQuotes?: boolean;
|
includeQuotes?: boolean;
|
||||||
|
/** @default true */
|
||||||
|
includeBots?: boolean;
|
||||||
/** @default 10 */
|
/** @default 10 */
|
||||||
limit?: number;
|
limit?: number;
|
||||||
/** Format: misskey:id */
|
/** Format: misskey:id */
|
||||||
|
@ -27242,6 +27244,8 @@ export type operations = {
|
||||||
/** @default true */
|
/** @default true */
|
||||||
withRenotes?: boolean;
|
withRenotes?: boolean;
|
||||||
/** @default true */
|
/** @default true */
|
||||||
|
withBots?: boolean;
|
||||||
|
/** @default true */
|
||||||
withNonPublic?: boolean;
|
withNonPublic?: boolean;
|
||||||
/** @default false */
|
/** @default false */
|
||||||
withChannelNotes?: boolean;
|
withChannelNotes?: boolean;
|
||||||
|
|
Loading…
Reference in a new issue