Merge remote-branch 'misskey/develop'

This commit is contained in:
NoriDev 2023-09-19 16:36:54 +09:00
commit 2b5ac6166d
7 changed files with 98 additions and 56 deletions

View file

@ -32,6 +32,8 @@
- ローカリゼーションの更新 - ローカリゼーションの更新
### Client ### Client
- 任意のユーザーリストをタイムラインページにピン留めできるように
- 設定->クライアント設定->全般 から設定可能です
- ノート詳細ページを改修 - ノート詳細ページを改修
- 読み込み時のパフォーマンスが向上しました - 読み込み時のパフォーマンスが向上しました
- リノート一覧、リアクション一覧がタブとして追加されました - リノート一覧、リアクション一覧がタブとして追加されました

1
locales/index.d.ts vendored
View file

@ -1182,6 +1182,7 @@ export interface Locale {
"renotes": string; "renotes": string;
"loadReplies": string; "loadReplies": string;
"loadConversation": string; "loadConversation": string;
"pinnedList": string;
"additionalPermissionsForFlash": string; "additionalPermissionsForFlash": string;
"thisFlashRequiresTheFollowingPermissions": string; "thisFlashRequiresTheFollowingPermissions": string;
"doYouWantToAllowThisPlayToAccessYourAccount": string; "doYouWantToAllowThisPlayToAccessYourAccount": string;

View file

@ -1179,6 +1179,7 @@ replies: "返信"
renotes: "リノート" renotes: "リノート"
loadReplies: "返信を見る" loadReplies: "返信を見る"
loadConversation: "会話を見る" loadConversation: "会話を見る"
pinnedList: "ピン留めされたリスト"
additionalPermissionsForFlash: "Playへの追加許可" additionalPermissionsForFlash: "Playへの追加許可"
thisFlashRequiresTheFollowingPermissions: "このPlayは以下の権限を要求しています" thisFlashRequiresTheFollowingPermissions: "このPlayは以下の権限を要求しています"
doYouWantToAllowThisPlayToAccessYourAccount: "このPlayによるアカウントへのアクセスを許可しますか" doYouWantToAllowThisPlayToAccessYourAccount: "このPlayによるアカウントへのアクセスを許可しますか"

View file

@ -30,6 +30,12 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkSwitch v-model="showFixedPostForm">{{ i18n.ts.showFixedPostForm }}</MkSwitch> <MkSwitch v-model="showFixedPostForm">{{ i18n.ts.showFixedPostForm }}</MkSwitch>
<MkSwitch v-model="showFixedPostFormInChannel">{{ i18n.ts.showFixedPostFormInChannel }}</MkSwitch> <MkSwitch v-model="showFixedPostFormInChannel">{{ i18n.ts.showFixedPostFormInChannel }}</MkSwitch>
<MkSwitch v-model="showTimelineReplies">{{ i18n.ts.flagShowTimelineReplies }}<template #caption>{{ i18n.ts.flagShowTimelineRepliesDescription }} {{ i18n.ts.reflectMayTakeTime }}</template></MkSwitch> <MkSwitch v-model="showTimelineReplies">{{ i18n.ts.flagShowTimelineReplies }}<template #caption>{{ i18n.ts.flagShowTimelineRepliesDescription }} {{ i18n.ts.reflectMayTakeTime }}</template></MkSwitch>
<MkFolder>
<template #label>{{ i18n.ts.pinnedList }}</template>
<!-- 複数ピン止め管理できるようにしたいけどめんどいので一旦ひとつのみ -->
<MkButton v-if="defaultStore.reactiveState.pinnedUserLists.value.length === 0" @click="setPinnedList()">{{ i18n.ts.add }}</MkButton>
<MkButton v-else danger @click="removePinnedList()"><i class="ti ti-trash"></i> {{ i18n.ts.remove }}</MkButton>
</MkFolder>
</div> </div>
</FormSection> </FormSection>
@ -424,6 +430,23 @@ function removeEmojiIndex(lang: string) {
os.promiseDialog(main()); os.promiseDialog(main());
} }
async function setPinnedList() {
const lists = await os.api('users/lists/list');
const { canceled, result: list } = await os.select({
title: i18n.ts.selectList,
items: lists.map(x => ({
value: x, text: x.name,
})),
});
if (canceled) return;
defaultStore.set('pinnedUserLists', [list]);
}
function removePinnedList() {
defaultStore.set('pinnedUserLists', []);
}
let smashCount = 0; let smashCount = 0;
let smashTimer: number | null = null; let smashTimer: number | null = null;
function testNotification(): void { function testNotification(): void {

View file

@ -35,7 +35,8 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkTimeline <MkTimeline
ref="tlComponent" ref="tlComponent"
:key="src" :key="src"
:src="src" :src="src.split(':')[0]"
:list="src.split(':')[1]"
:sound="true" :sound="true"
@queue="queueUpdated" @queue="queueUpdated"
/> />
@ -92,20 +93,20 @@ let queue = $ref(0);
let srcWhenNotSignin = $ref(isLocalTimelineAvailable ? 'local' : 'global'); let srcWhenNotSignin = $ref(isLocalTimelineAvailable ? 'local' : 'global');
const src = $computed({ get: () => ($i ? defaultStore.reactiveState.tl.value.src : srcWhenNotSignin), set: (x) => saveSrc(x) }); const src = $computed({ get: () => ($i ? defaultStore.reactiveState.tl.value.src : srcWhenNotSignin), set: (x) => saveSrc(x) });
watch ($$(src), () => { watch($$(src), () => {
queue = 0; queue = 0;
queueUpdated(queue); queueUpdated(queue);
}); });
onMounted(() => { onMounted(() => {
globalEvents.on('showEl', (showEl_receive) => { globalEvents.on('showEl', (showEl_receive) => {
showEl = showEl_receive; showEl = showEl_receive;
}); });
}); });
function queueUpdated(q: number): void { function queueUpdated(q: number): void {
queue = q; queue = q;
globalEvents.emit('queueUpdated', q); globalEvents.emit('queueUpdated', q);
} }
function top(): void { function top(): void {
@ -146,10 +147,15 @@ async function chooseChannel(ev: MouseEvent): Promise<void> {
os.popupMenu(items, ev.currentTarget ?? ev.target); os.popupMenu(items, ev.currentTarget ?? ev.target);
} }
function saveSrc(newSrc: 'home' | 'local' | 'media' | 'social' | 'cat' | 'global'): void { function saveSrc(newSrc: 'home' | 'local' | 'media' | 'social' | 'cat' | 'global' | `list:${string}`): void {
let userList = null;
if (newSrc.startsWith('userList:')) {
const id = newSrc.substring('userList:'.length);
userList = defaultStore.reactiveState.pinnedUserLists.value.find(l => l.id === id);
}
defaultStore.set('tl', { defaultStore.set('tl', {
...defaultStore.state.tl,
src: newSrc, src: newSrc,
userList,
}); });
srcWhenNotSignin = newSrc; srcWhenNotSignin = newSrc;
} }
@ -198,53 +204,57 @@ const headerActions = $computed(() => [{
const friendlyEnableNotifications = computed(defaultStore.makeGetterSetter('friendlyEnableNotifications')); const friendlyEnableNotifications = computed(defaultStore.makeGetterSetter('friendlyEnableNotifications'));
const friendlyEnableWidgets = computed(defaultStore.makeGetterSetter('friendlyEnableWidgets')); const friendlyEnableWidgets = computed(defaultStore.makeGetterSetter('friendlyEnableWidgets'));
const headerTabs = $computed(() => [ const headerTabs = $computed(() => [...(defaultStore.reactiveState.pinnedUserLists.value.map(l => ({
...(defaultStore.state.enableHomeTimeline ? [{ key: 'list:' + l.id,
key: 'home', title: l.name,
title: i18n.ts._timelines.home, icon: 'ti ti-star',
icon: 'ti ti-home', iconOnly: true,
iconOnly: true, }))), ...(defaultStore.state.enableHomeTimeline ? [{
}] : []), ...(isLocalTimelineAvailable && defaultStore.state.enableLocalTimeline ? [{ key: 'home',
key: 'local', title: i18n.ts._timelines.home,
title: i18n.ts._timelines.local, icon: 'ti ti-home',
icon: 'ti ti-planet', iconOnly: true,
iconOnly: true, }] : []), ...(isLocalTimelineAvailable && defaultStore.state.enableLocalTimeline ? [{
}, ...(isMediaTimelineAvailable && defaultStore.state.enableMediaTimeline ? [{ key: 'local',
key: 'media', title: i18n.ts._timelines.local,
title: i18n.ts._timelines.media, icon: 'ti ti-planet',
icon: 'ti ti-photo', iconOnly: true,
iconOnly: true, }, ...(isMediaTimelineAvailable && defaultStore.state.enableMediaTimeline ? [{
}] : []), ...(defaultStore.state.enableSocialTimeline ? [{ key: 'media',
key: 'social', title: i18n.ts._timelines.media,
title: i18n.ts._timelines.social, icon: 'ti ti-photo',
icon: 'ti ti-rocket', iconOnly: true,
iconOnly: true, }] : []), ...(defaultStore.state.enableSocialTimeline ? [{
}] : []), ...(isCatTimelineAvailable && defaultStore.state.enableCatTimeline ? [{ key: 'social',
key: 'cat', title: i18n.ts._timelines.social,
title: i18n.ts._timelines.cat, icon: 'ti ti-rocket',
icon: 'ti ti-cat', iconOnly: true,
iconOnly: true, }] : []), ...(isCatTimelineAvailable && defaultStore.state.enableCatTimeline ? [{
}] : [])] : []), ...(isGlobalTimelineAvailable && defaultStore.state.enableGlobalTimeline ? [{ key: 'cat',
key: 'global', title: i18n.ts._timelines.cat,
title: i18n.ts._timelines.global, icon: 'ti ti-cat',
icon: 'ti ti-world', iconOnly: true,
iconOnly: true, }] : [])] : []), ...(isGlobalTimelineAvailable && defaultStore.state.enableGlobalTimeline ? [{
}] : []), ...(defaultStore.state.enableListTimeline ? [{ key: 'global',
icon: 'ti ti-list', title: i18n.ts._timelines.global,
title: i18n.ts.lists, icon: 'ti ti-world',
iconOnly: true, iconOnly: true,
onClick: chooseList, }] : []), ...(defaultStore.state.enableListTimeline ? [{
}] : []), ...(defaultStore.state.enableAntennaTimeline ? [{ icon: 'ti ti-list',
icon: 'ti ti-antenna', title: i18n.ts.lists,
title: i18n.ts.antennas, iconOnly: true,
iconOnly: true, onClick: chooseList,
onClick: chooseAntenna, }] : []), ...(defaultStore.state.enableAntennaTimeline ? [{
}] : []), ...(defaultStore.state.enableChannelTimeline ? [{ icon: 'ti ti-antenna',
icon: 'ti ti-device-tv', title: i18n.ts.antennas,
title: i18n.ts.channel, iconOnly: true,
iconOnly: true, onClick: chooseAntenna,
onClick: chooseChannel, }] : []), ...(defaultStore.state.enableChannelTimeline ? [{
}] : [])] as Tab[]); icon: 'ti ti-device-tv',
title: i18n.ts.channel,
iconOnly: true,
onClick: chooseChannel,
}] : [])] as Tab[]);
const headerTabsWhenNotLogin = $computed(() => [ const headerTabsWhenNotLogin = $computed(() => [
...(isLocalTimelineAvailable ? [{ ...(isLocalTimelineAvailable ? [{

View file

@ -4,7 +4,7 @@
*/ */
import { markRaw, ref } from 'vue'; import { markRaw, ref } from 'vue';
import Misskey from 'cherrypick-js'; import * as Misskey from 'cherrypick-js';
import { Storage } from './pizzax'; import { Storage } from './pizzax';
interface PostFormAction { interface PostFormAction {
@ -188,10 +188,14 @@ export const defaultStore = markRaw(new Storage('base', {
tl: { tl: {
where: 'deviceAccount', where: 'deviceAccount',
default: { default: {
src: 'home' as 'home' | 'local' | 'social' | 'global', src: 'home' as 'home' | 'local' | 'social' | 'global' | `list:${string}`,
arg: null, userList: null as Misskey.entities.UserList | null,
}, },
}, },
pinnedUserLists: {
where: 'deviceAccount',
default: [] as Misskey.entities.UserList[],
},
overridedDeviceKind: { overridedDeviceKind: {
where: 'device', where: 'device',

View file

@ -64,6 +64,7 @@ module.exports = {
'object-curly-spacing': ['error', 'always'], 'object-curly-spacing': ['error', 'always'],
'space-infix-ops': ['error'], 'space-infix-ops': ['error'],
'space-before-blocks': ['error', 'always'], 'space-before-blocks': ['error', 'always'],
'@typescript-eslint/func-call-spacing': ['error', 'never'],
'@typescript-eslint/no-explicit-any': ['warn'], '@typescript-eslint/no-explicit-any': ['warn'],
'@typescript-eslint/no-unused-vars': ['warn'], '@typescript-eslint/no-unused-vars': ['warn'],
'@typescript-eslint/no-unnecessary-condition': ['warn'], '@typescript-eslint/no-unnecessary-condition': ['warn'],