Merge branch 'develop' into feat-1714

This commit is contained in:
かっこかり 2024-07-31 21:00:34 +09:00 committed by GitHub
commit 24c7fb38a0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
165 changed files with 6316 additions and 4265 deletions

View file

@ -0,0 +1,19 @@
/*
* SPDX-FileCopyrightText: syuilo and misskey-project
* SPDX-License-Identifier: AGPL-3.0-only
*/
import { instance } from '@/instance.js';
import { $i } from '@/account.js';
export const notesSearchAvailable = (
// FIXME: instance.policies would be null in Vitest
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
($i == null && instance.policies != null && instance.policies.canSearchNotes) ||
($i != null && $i.policies.canSearchNotes) ||
false
) as boolean;
export const canSearchNonLocalNotes = (
instance.noteSearchableScope === 'global'
);

View file

@ -41,6 +41,15 @@ function describe(file: Misskey.entities.DriveFile) {
});
}
function move(file: Misskey.entities.DriveFile) {
os.selectDriveFolder(false).then(folder => {
misskeyApi('drive/files/update', {
fileId: file.id,
folderId: folder[0] ? folder[0].id : null,
});
});
}
function toggleSensitive(file: Misskey.entities.DriveFile) {
misskeyApi('drive/files/update', {
fileId: file.id,
@ -88,6 +97,10 @@ export function getDriveFileMenu(file: Misskey.entities.DriveFile, folder?: Miss
text: i18n.ts.rename,
icon: 'ti ti-forms',
action: () => rename(file),
}, {
text: i18n.ts.move,
icon: 'ti ti-folder-symlink',
action: () => move(file),
}, {
text: file.isSensitive ? i18n.ts.unmarkAsSensitive : i18n.ts.markAsSensitive,
icon: file.isSensitive ? 'ti ti-eye' : 'ti ti-eye-exclamation',

View file

@ -13,10 +13,12 @@ import * as os from '@/os.js';
import { misskeyApi } from '@/scripts/misskey-api.js';
import { defaultStore, userActions } from '@/store.js';
import { $i, iAmModerator } from '@/account.js';
import { notesSearchAvailable, canSearchNonLocalNotes } from '@/scripts/check-permissions.js';
import { IRouter } from '@/nirax.js';
import { antennasCache, rolesCache, userListsCache } from '@/cache.js';
import { mainRouter } from '@/router/main.js';
import { copyEmbedCode } from '@/scripts/get-embed-code.js';
import { MenuItem } from '@/types/menu.js';
export function getUserMenu(user: Misskey.entities.UserDetailed, router: IRouter = mainRouter) {
const meId = $i ? $i.id : null;
@ -82,15 +84,6 @@ export function getUserMenu(user: Misskey.entities.UserDetailed, router: IRouter
});
}
async function toggleWithReplies() {
os.apiWithDialog('following/update', {
userId: user.id,
withReplies: !user.withReplies,
}).then(() => {
user.withReplies = !user.withReplies;
});
}
async function toggleNotify() {
os.apiWithDialog('following/update', {
userId: user.id,
@ -155,13 +148,20 @@ export function getUserMenu(user: Misskey.entities.UserDetailed, router: IRouter
});
}
let menu = [{
let menu: MenuItem[] = [{
icon: 'ti ti-at',
text: i18n.ts.copyUsername,
action: () => {
copyToClipboard(`@${user.username}@${user.host ?? host}`);
},
}, ...(iAmModerator ? [{
}, ...( notesSearchAvailable && (user.host == null || canSearchNonLocalNotes) ? [{
icon: 'ti ti-search',
text: i18n.ts.searchThisUsersNotes,
action: () => {
router.push(`/search?username=${encodeURIComponent(user.username)}${user.host != null ? '&host=' + encodeURIComponent(user.host) : ''}`);
},
}] : [])
, ...(iAmModerator ? [{
icon: 'ti ti-user-exclamation',
text: i18n.ts.moderation,
action: () => {
@ -317,15 +317,25 @@ export function getUserMenu(user: Misskey.entities.UserDetailed, router: IRouter
// フォローしたとしても user.isFollowing はリアルタイム更新されないので不便なため
//if (user.isFollowing) {
const withRepliesRef = ref(user.withReplies);
menu = menu.concat([{
icon: user.withReplies ? 'ti ti-messages-off' : 'ti ti-messages',
text: user.withReplies ? i18n.ts.hideRepliesToOthersInTimeline : i18n.ts.showRepliesToOthersInTimeline,
action: toggleWithReplies,
type: 'switch',
icon: 'ti ti-messages',
text: i18n.ts.showRepliesToOthersInTimeline,
ref: withRepliesRef,
}, {
icon: user.notify === 'none' ? 'ti ti-bell' : 'ti ti-bell-off',
text: user.notify === 'none' ? i18n.ts.notifyNotes : i18n.ts.unnotifyNotes,
action: toggleNotify,
}]);
watch(withRepliesRef, (withReplies) => {
misskeyApi('following/update', {
userId: user.id,
withReplies,
}).then(() => {
user.withReplies = withReplies;
});
});
//}
menu = menu.concat([{ type: 'divider' }, {

View file

@ -16,7 +16,7 @@ export async function lookup(router?: Router) {
title: i18n.ts.lookup,
});
const query = temp ? temp.trim() : '';
if (canceled) return;
if (canceled || query.length <= 1) return;
if (query.startsWith('@') && !query.includes(' ')) {
_router.push(`/${query}`);

View file

@ -6,7 +6,7 @@
import { deepClone } from './clone.js';
import type { Cloneable } from './clone.js';
type DeepPartial<T> = {
export type DeepPartial<T> = {
[P in keyof T]?: T[P] extends Record<string | number | symbol, unknown> ? DeepPartial<T[P]> : T[P];
};

View file

@ -124,14 +124,16 @@ export async function loadAudio(url: string, options?: { useCache?: boolean; })
*/
export function playMisskeySfx(operationType: OperationType) {
const sound = defaultStore.state[`sound_${operationType}`];
if (sound.type == null || !canPlay || ('userActivation' in navigator && !navigator.userActivation.hasBeenActive)) return;
canPlay = false;
playMisskeySfxFile(sound).finally(() => {
// ごく短時間に音が重複しないように
setTimeout(() => {
canPlay = true;
}, 25);
playMisskeySfxFile(sound).then((succeed) => {
if (!succeed && sound.type === '_driveFile_') {
// ドライブファイルが存在しない場合はデフォルトのサウンドを再生する
const soundName = defaultStore.def[`sound_${operationType}`].default.type as Exclude<SoundType, '_driveFile_'>;
if (_DEV_) console.log(`Failed to play sound: ${sound.fileUrl}, so play default sound: ${soundName}`);
playMisskeySfxFileInternal({
type: soundName,
volume: sound.volume,
});
}
});
}
@ -139,19 +141,39 @@ export function playMisskeySfx(operationType: OperationType) {
*
* @param soundStore
*/
export async function playMisskeySfxFile(soundStore: SoundStore) {
export async function playMisskeySfxFile(soundStore: SoundStore): Promise<boolean> {
// 連続して再生しない
if (!canPlay) return false;
// ユーザーアクティベーションが必要な場合はそれがない場合は再生しない
if ('userActivation' in navigator && !navigator.userActivation.hasBeenActive) return false;
// サウンドがない場合は再生しない
if (soundStore.type === null || soundStore.type === '_driveFile_' && !soundStore.fileUrl) return false;
canPlay = false;
return await playMisskeySfxFileInternal(soundStore).finally(() => {
// ごく短時間に音が重複しないように
setTimeout(() => {
canPlay = true;
}, 25);
});
}
async function playMisskeySfxFileInternal(soundStore: SoundStore): Promise<boolean> {
if (soundStore.type === null || (soundStore.type === '_driveFile_' && !soundStore.fileUrl)) {
return;
return false;
}
const masterVolume = defaultStore.state.sound_masterVolume;
if (isMute() || masterVolume === 0 || soundStore.volume === 0) {
return;
return true; // ミュート時は成功として扱う
}
const url = soundStore.type === '_driveFile_' ? soundStore.fileUrl : `/client-assets/sounds/${soundStore.type}.mp3`;
const buffer = await loadAudio(url);
if (!buffer) return;
const buffer = await loadAudio(url).catch(() => {
return undefined;
});
if (!buffer) return false;
const volume = soundStore.volume * masterVolume;
createSourceNode(buffer, { volume }).soundSource.start();
return true;
}
export async function playUrl(url: string, opts: {