Merge branch 'develop' into watermark

This commit is contained in:
syuilo 2025-06-03 18:47:23 +09:00 committed by GitHub
commit 3bbba7356c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 41 additions and 2 deletions

View File

@ -5,6 +5,7 @@
### Client ### Client
- Feat: 画像にウォーターマークを付与できるようになりました - Feat: 画像にウォーターマークを付与できるようになりました
- Enhance: ノートのリアクション一覧で、押せるリアクションを優先して表示できるようにするオプションを追加
- Fix: ドライブファイルの選択が不安定な問題を修正 - Fix: ドライブファイルの選択が不安定な問題を修正
- Fix: コントロールパネルのファイル欄などのデザインが崩れている問題を修正 - Fix: コントロールパネルのファイル欄などのデザインが崩れている問題を修正
- Fix: ユーザーの検索結果を追加で読み込むことができない問題を修正 - Fix: ユーザーの検索結果を追加で読み込むことができない問題を修正

4
locales/index.d.ts vendored
View File

@ -5829,6 +5829,10 @@ export interface Locale extends ILocale {
* URLプレビューを表示する * URLプレビューを表示する
*/ */
"showUrlPreview": string; "showUrlPreview": string;
/**
*
*/
"showAvailableReactionsFirstInNote": string;
"_chat": { "_chat": {
/** /**
* *

View File

@ -1457,6 +1457,7 @@ _settings:
contentsUpdateFrequency_description: "高いほどリアルタイムにコンテンツが更新されますが、パフォーマンスが低下し、通信量とバッテリーの消費が多くなります。" contentsUpdateFrequency_description: "高いほどリアルタイムにコンテンツが更新されますが、パフォーマンスが低下し、通信量とバッテリーの消費が多くなります。"
contentsUpdateFrequency_description2: "リアルタイムモードがオンのときは、この設定に関わらずリアルタイムでコンテンツが更新されます。" contentsUpdateFrequency_description2: "リアルタイムモードがオンのときは、この設定に関わらずリアルタイムでコンテンツが更新されます。"
showUrlPreview: "URLプレビューを表示する" showUrlPreview: "URLプレビューを表示する"
showAvailableReactionsFirstInNote: "利用できるリアクションを先頭に表示"
_chat: _chat:
showSenderName: "送信者の名前を表示" showSenderName: "送信者の名前を表示"

View File

@ -48,6 +48,10 @@ export function getUnicodeEmoji(char: string): UnicodeEmojiDef | string {
?? char; ?? char;
} }
export function isSupportedEmoji(char: string): boolean {
return unicodeEmojisMap.has(colorizeEmoji(char)) || unicodeEmojisMap.has(char);
}
export function getEmojiName(char: string): string { export function getEmojiName(char: string): string {
// Colorize it because emojilist.json assumes that // Colorize it because emojilist.json assumes that
const idx = _indexByChar.get(colorizeEmoji(char)) ?? _indexByChar.get(char); const idx = _indexByChar.get(colorizeEmoji(char)) ?? _indexByChar.get(char);

View File

@ -33,7 +33,10 @@ import * as Misskey from 'misskey-js';
import { inject, watch, ref } from 'vue'; import { inject, watch, ref } from 'vue';
import { TransitionGroup } from 'vue'; import { TransitionGroup } from 'vue';
import XReaction from '@/components/MkReactionsViewer.reaction.vue'; import XReaction from '@/components/MkReactionsViewer.reaction.vue';
import { $i } from '@/i.js';
import { prefer } from '@/preferences.js'; import { prefer } from '@/preferences.js';
import { customEmojisMap } from '@/custom-emojis.js';
import { isSupportedEmoji } from '@@/js/emojilist.js';
import { DI } from '@/di.js'; import { DI } from '@/di.js';
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
@ -70,6 +73,12 @@ function onMockToggleReaction(emoji: string, count: number) {
emit('mockUpdateMyReaction', emoji, (count - _reactions.value[i][1])); emit('mockUpdateMyReaction', emoji, (count - _reactions.value[i][1]));
} }
function canReact(reaction: string) {
if (!$i) return false;
// TODO: CheckPermissions
return !reaction.match(/@\w/) && (customEmojisMap.has(reaction) || isSupportedEmoji(reaction));
}
watch([() => props.reactions, () => props.maxNumber], ([newSource, maxNumber]) => { watch([() => props.reactions, () => props.maxNumber], ([newSource, maxNumber]) => {
let newReactions: [string, number][] = []; let newReactions: [string, number][] = [];
hasMoreReactions.value = Object.keys(newSource).length > maxNumber; hasMoreReactions.value = Object.keys(newSource).length > maxNumber;
@ -86,7 +95,15 @@ watch([() => props.reactions, () => props.maxNumber], ([newSource, maxNumber]) =
newReactions = [ newReactions = [
...newReactions, ...newReactions,
...Object.entries(newSource) ...Object.entries(newSource)
.sort(([, a], [, b]) => b - a) .sort(([emojiA, countA], [emojiB, countB]) => {
if (prefer.s.showAvailableReactionsFirstInNote) {
if (!canReact(emojiA) && canReact(emojiB)) return 1;
if (canReact(emojiA) && !canReact(emojiB)) return -1;
return countB - countA;
} else {
return countB - countA;
}
})
.filter(([y], i) => i < maxNumber && !newReactionsNames.includes(y)), .filter(([y], i) => i < maxNumber && !newReactionsNames.includes(y)),
]; ];

View File

@ -229,6 +229,14 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkSwitch> </MkSwitch>
</MkPreferenceContainer> </MkPreferenceContainer>
</SearchMarker> </SearchMarker>
<SearchMarker :keywords="['reaction', 'order']">
<MkPreferenceContainer k="showAvailableReactionsFirstInNote">
<MkSwitch v-model="showAvailableReactionsFirstInNote">
<template #label><SearchLabel>{{ i18n.ts._settings.showAvailableReactionsFirstInNote }}</SearchLabel></template>
</MkSwitch>
</MkPreferenceContainer>
</SearchMarker>
</div> </div>
<SearchMarker :keywords="['reaction', 'size', 'scale', 'display']"> <SearchMarker :keywords="['reaction', 'size', 'scale', 'display']">
@ -824,6 +832,7 @@ const showFixedPostFormInChannel = prefer.model('showFixedPostFormInChannel');
const numberOfPageCache = prefer.model('numberOfPageCache'); const numberOfPageCache = prefer.model('numberOfPageCache');
const enableInfiniteScroll = prefer.model('enableInfiniteScroll'); const enableInfiniteScroll = prefer.model('enableInfiniteScroll');
const useReactionPickerForContextMenu = prefer.model('useReactionPickerForContextMenu'); const useReactionPickerForContextMenu = prefer.model('useReactionPickerForContextMenu');
const showAvailableReactionsFirstInNote = prefer.model('showAvailableReactionsFirstInNote');
const useGroupedNotifications = prefer.model('useGroupedNotifications'); const useGroupedNotifications = prefer.model('useGroupedNotifications');
const alwaysConfirmFollow = prefer.model('alwaysConfirmFollow'); const alwaysConfirmFollow = prefer.model('alwaysConfirmFollow');
const confirmWhenRevealingSensitiveMedia = prefer.model('confirmWhenRevealingSensitiveMedia'); const confirmWhenRevealingSensitiveMedia = prefer.model('confirmWhenRevealingSensitiveMedia');
@ -900,7 +909,6 @@ watch([
reactionsDisplaySize, reactionsDisplaySize,
limitWidthOfReaction, limitWidthOfReaction,
mediaListWithOneImageAppearance, mediaListWithOneImageAppearance,
reactionsDisplaySize,
limitWidthOfReaction, limitWidthOfReaction,
instanceTicker, instanceTicker,
squareAvatars, squareAvatars,
@ -917,6 +925,7 @@ watch([
enableHorizontalSwipe, enableHorizontalSwipe,
enablePullToRefresh, enablePullToRefresh,
reduceAnimation, reduceAnimation,
showAvailableReactionsFirstInNote,
], async () => { ], async () => {
await reloadAsk({ reason: i18n.ts.reloadToApplySetting, unison: true }); await reloadAsk({ reason: i18n.ts.reloadToApplySetting, unison: true });
}); });

View File

@ -378,6 +378,9 @@ export const PREF_DEF = definePreferences({
showTitlebar: { showTitlebar: {
default: false, default: false,
}, },
showAvailableReactionsFirstInNote: {
default: false,
},
plugins: { plugins: {
default: [] as Plugin[], default: [] as Plugin[],
mergeStrategy: (a, b) => { mergeStrategy: (a, b) => {