Merge remote-tracking branch 'misskey-dev/develop' into develop
This commit is contained in:
commit
9b7be06eef
20
CHANGELOG.md
20
CHANGELOG.md
@ -10,6 +10,26 @@
|
|||||||
You should also include the user name that made the change.
|
You should also include the user name that made the change.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
|
## 12.106.3 (2022/02/11)
|
||||||
|
|
||||||
|
### Improvements
|
||||||
|
- クライアント: スマートフォンでの余白を調整 @syuilo
|
||||||
|
|
||||||
|
### Bugfixes
|
||||||
|
- クライアント: ノートの詳細が表示されない問題を修正 @syuilo
|
||||||
|
|
||||||
|
## 12.106.2 (2022/02/11)
|
||||||
|
|
||||||
|
### Bugfixes
|
||||||
|
- クライアント: 削除したノートがタイムラインから自動で消えない問題を修正 @syuilo
|
||||||
|
- クライアント: リアクション数が正しくないことがある問題を修正 @syuilo
|
||||||
|
- 一部環境でマイグレーションが動作しない問題を修正 @syuilo
|
||||||
|
|
||||||
|
## 12.106.1 (2022/02/11)
|
||||||
|
|
||||||
|
### Bugfixes
|
||||||
|
- クライアント: ワードミュートが保存できない問題を修正 @syuilo
|
||||||
|
|
||||||
## 12.106.0 (2022/02/11)
|
## 12.106.0 (2022/02/11)
|
||||||
|
|
||||||
### Improvements
|
### Improvements
|
||||||
|
@ -831,6 +831,8 @@ smartphone: "智能手机"
|
|||||||
tablet: "平板"
|
tablet: "平板"
|
||||||
auto: "自动"
|
auto: "自动"
|
||||||
themeColor: "主题颜色"
|
themeColor: "主题颜色"
|
||||||
|
size: "大小"
|
||||||
|
numberOfColumn: "列数"
|
||||||
_emailUnavailable:
|
_emailUnavailable:
|
||||||
used: "已经被使用过"
|
used: "已经被使用过"
|
||||||
format: "无效的格式"
|
format: "无效的格式"
|
||||||
@ -958,7 +960,7 @@ _mfm:
|
|||||||
rotateDescription: "旋转指定的角度。"
|
rotateDescription: "旋转指定的角度。"
|
||||||
_instanceTicker:
|
_instanceTicker:
|
||||||
none: "不显示"
|
none: "不显示"
|
||||||
remote: "显示给远程用户"
|
remote: "仅显示远程用户的"
|
||||||
always: "始终显示"
|
always: "始终显示"
|
||||||
_serverDisconnectedBehavior:
|
_serverDisconnectedBehavior:
|
||||||
reload: "自动重载"
|
reload: "自动重载"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "misskey",
|
"name": "misskey",
|
||||||
"version": "12.106.0-simkey",
|
"version": "12.106.3-simkey",
|
||||||
"codename": "indigo",
|
"codename": "indigo",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
@ -5,10 +5,11 @@ module.exports = class convertHardMutes1644010796173 {
|
|||||||
name = 'convertHardMutes1644010796173'
|
name = 'convertHardMutes1644010796173'
|
||||||
|
|
||||||
async up(queryRunner) {
|
async up(queryRunner) {
|
||||||
let entries = await queryRunner.query(`SELECT "userId", "mutedWords" FROM "user_profile"`);
|
let entries = await queryRunner.query(`SELECT "userId", "mutedWords" FROM "user_profile" WHERE "userHost" IS NULL`);
|
||||||
for(let i = 0; i < entries.length; i++) {
|
for(let i = 0; i < entries.length; i++) {
|
||||||
let words = entries[i].mutedWords
|
let words = entries[i].mutedWords
|
||||||
.map(line => {
|
.map(line => {
|
||||||
|
if (typeof line === 'string') return [];
|
||||||
const regexp = line.join(" ").match(/^\/(.+)\/(.*)$/);
|
const regexp = line.join(" ").match(/^\/(.+)\/(.*)$/);
|
||||||
if (regexp) {
|
if (regexp) {
|
||||||
// convert regexp's
|
// convert regexp's
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { deviceKind } from '@/scripts/device-kind';
|
||||||
import { defineComponent, inject, onMounted, onUnmounted, ref } from 'vue';
|
import { defineComponent, inject, onMounted, onUnmounted, ref } from 'vue';
|
||||||
|
|
||||||
export default defineComponent({
|
export default defineComponent({
|
||||||
@ -35,7 +36,7 @@ export default defineComponent({
|
|||||||
const margin = ref(0);
|
const margin = ref(0);
|
||||||
const shouldSpacerMin = inject('shouldSpacerMin', false);
|
const shouldSpacerMin = inject('shouldSpacerMin', false);
|
||||||
const adjust = (rect: { width: number; height: number; }) => {
|
const adjust = (rect: { width: number; height: number; }) => {
|
||||||
if (shouldSpacerMin) {
|
if (shouldSpacerMin || deviceKind === 'smartphone') {
|
||||||
margin.value = props.marginMin;
|
margin.value = props.marginMin;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -154,11 +154,13 @@ const props = defineProps<{
|
|||||||
|
|
||||||
const inChannel = inject('inChannel', null);
|
const inChannel = inject('inChannel', null);
|
||||||
|
|
||||||
|
const note = $ref(JSON.parse(JSON.stringify(props.note)));
|
||||||
|
|
||||||
const isRenote = (
|
const isRenote = (
|
||||||
props.note.renote != null &&
|
note.renote != null &&
|
||||||
props.note.text == null &&
|
note.text == null &&
|
||||||
props.note.fileIds.length === 0 &&
|
note.fileIds.length === 0 &&
|
||||||
props.note.poll == null
|
note.poll == null
|
||||||
);
|
);
|
||||||
|
|
||||||
const el = ref<HTMLElement>();
|
const el = ref<HTMLElement>();
|
||||||
@ -166,8 +168,8 @@ const menuButton = ref<HTMLElement>();
|
|||||||
const renoteButton = ref<InstanceType<typeof XRenoteButton>>();
|
const renoteButton = ref<InstanceType<typeof XRenoteButton>>();
|
||||||
const renoteTime = ref<HTMLElement>();
|
const renoteTime = ref<HTMLElement>();
|
||||||
const reactButton = ref<HTMLElement>();
|
const reactButton = ref<HTMLElement>();
|
||||||
let appearNote = $ref(isRenote ? props.note.renote as misskey.entities.Note : props.note);
|
let appearNote = $ref(isRenote ? note.renote as misskey.entities.Note : note);
|
||||||
const isMyRenote = $i && ($i.id === props.note.userId);
|
const isMyRenote = $i && ($i.id === note.userId);
|
||||||
const showContent = ref(false);
|
const showContent = ref(false);
|
||||||
const isDeleted = ref(false);
|
const isDeleted = ref(false);
|
||||||
const muted = ref(checkWordMute(appearNote, $i, defaultStore.state.mutedWords));
|
const muted = ref(checkWordMute(appearNote, $i, defaultStore.state.mutedWords));
|
||||||
@ -188,8 +190,9 @@ const keymap = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
useNoteCapture({
|
useNoteCapture({
|
||||||
appearNote: $$(appearNote),
|
|
||||||
rootEl: el,
|
rootEl: el,
|
||||||
|
note: $$(appearNote),
|
||||||
|
isDeletedRef: isDeleted,
|
||||||
});
|
});
|
||||||
|
|
||||||
function reply(viaKeyboard = false): void {
|
function reply(viaKeyboard = false): void {
|
||||||
@ -237,12 +240,12 @@ function onContextmenu(ev: MouseEvent): void {
|
|||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
react();
|
react();
|
||||||
} else {
|
} else {
|
||||||
os.contextMenu(getNoteMenu({ note: props.note, translating, translation, menuButton }), ev).then(focus);
|
os.contextMenu(getNoteMenu({ note: note, translating, translation, menuButton }), ev).then(focus);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function menu(viaKeyboard = false): void {
|
function menu(viaKeyboard = false): void {
|
||||||
os.popupMenu(getNoteMenu({ note: props.note, translating, translation, menuButton }), menuButton.value, {
|
os.popupMenu(getNoteMenu({ note: note, translating, translation, menuButton }), menuButton.value, {
|
||||||
viaKeyboard
|
viaKeyboard
|
||||||
}).then(focus);
|
}).then(focus);
|
||||||
}
|
}
|
||||||
@ -255,7 +258,7 @@ function showRenoteMenu(viaKeyboard = false): void {
|
|||||||
danger: true,
|
danger: true,
|
||||||
action: () => {
|
action: () => {
|
||||||
os.api('notes/delete', {
|
os.api('notes/delete', {
|
||||||
noteId: props.note.id
|
noteId: note.id
|
||||||
});
|
});
|
||||||
isDeleted.value = true;
|
isDeleted.value = true;
|
||||||
}
|
}
|
||||||
|
@ -138,11 +138,13 @@ const props = defineProps<{
|
|||||||
|
|
||||||
const inChannel = inject('inChannel', null);
|
const inChannel = inject('inChannel', null);
|
||||||
|
|
||||||
|
const note = $ref(JSON.parse(JSON.stringify(props.note)));
|
||||||
|
|
||||||
const isRenote = (
|
const isRenote = (
|
||||||
props.note.renote != null &&
|
note.renote != null &&
|
||||||
props.note.text == null &&
|
note.text == null &&
|
||||||
props.note.fileIds.length === 0 &&
|
note.fileIds.length === 0 &&
|
||||||
props.note.poll == null
|
note.poll == null
|
||||||
);
|
);
|
||||||
|
|
||||||
const el = ref<HTMLElement>();
|
const el = ref<HTMLElement>();
|
||||||
@ -150,8 +152,8 @@ const menuButton = ref<HTMLElement>();
|
|||||||
const renoteButton = ref<InstanceType<typeof XRenoteButton>>();
|
const renoteButton = ref<InstanceType<typeof XRenoteButton>>();
|
||||||
const renoteTime = ref<HTMLElement>();
|
const renoteTime = ref<HTMLElement>();
|
||||||
const reactButton = ref<HTMLElement>();
|
const reactButton = ref<HTMLElement>();
|
||||||
let appearNote = $ref(isRenote ? props.note.renote as misskey.entities.Note : props.note);
|
let appearNote = $ref(isRenote ? note.renote as misskey.entities.Note : note);
|
||||||
const isMyRenote = $i && ($i.id === props.note.userId);
|
const isMyRenote = $i && ($i.id === note.userId);
|
||||||
const showContent = ref(false);
|
const showContent = ref(false);
|
||||||
const collapsed = ref(appearNote.cw == null && appearNote.text != null && (
|
const collapsed = ref(appearNote.cw == null && appearNote.text != null && (
|
||||||
(appearNote.text.split('\n').length > 9) ||
|
(appearNote.text.split('\n').length > 9) ||
|
||||||
@ -176,8 +178,9 @@ const keymap = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
useNoteCapture({
|
useNoteCapture({
|
||||||
appearNote: $$(appearNote),
|
|
||||||
rootEl: el,
|
rootEl: el,
|
||||||
|
note: $$(appearNote),
|
||||||
|
isDeletedRef: isDeleted,
|
||||||
});
|
});
|
||||||
|
|
||||||
function reply(viaKeyboard = false): void {
|
function reply(viaKeyboard = false): void {
|
||||||
@ -225,12 +228,12 @@ function onContextmenu(ev: MouseEvent): void {
|
|||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
react();
|
react();
|
||||||
} else {
|
} else {
|
||||||
os.contextMenu(getNoteMenu({ note: props.note, translating, translation, menuButton }), ev).then(focus);
|
os.contextMenu(getNoteMenu({ note: note, translating, translation, menuButton }), ev).then(focus);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function menu(viaKeyboard = false): void {
|
function menu(viaKeyboard = false): void {
|
||||||
os.popupMenu(getNoteMenu({ note: props.note, translating, translation, menuButton }), menuButton.value, {
|
os.popupMenu(getNoteMenu({ note: note, translating, translation, menuButton }), menuButton.value, {
|
||||||
viaKeyboard
|
viaKeyboard
|
||||||
}).then(focus);
|
}).then(focus);
|
||||||
}
|
}
|
||||||
@ -243,7 +246,7 @@ function showRenoteMenu(viaKeyboard = false): void {
|
|||||||
danger: true,
|
danger: true,
|
||||||
action: () => {
|
action: () => {
|
||||||
os.api('notes/delete', {
|
os.api('notes/delete', {
|
||||||
noteId: props.note.id
|
noteId: note.id
|
||||||
});
|
});
|
||||||
isDeleted.value = true;
|
isDeleted.value = true;
|
||||||
}
|
}
|
||||||
|
@ -124,6 +124,8 @@ export default defineComponent({
|
|||||||
lines[i] = line.split(' ');
|
lines[i] = line.split(' ');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return lines;
|
||||||
};
|
};
|
||||||
|
|
||||||
let softMutes, hardMutes;
|
let softMutes, hardMutes;
|
||||||
|
@ -5,34 +5,35 @@ import { $i } from '@/account';
|
|||||||
|
|
||||||
export function useNoteCapture(props: {
|
export function useNoteCapture(props: {
|
||||||
rootEl: Ref<HTMLElement>;
|
rootEl: Ref<HTMLElement>;
|
||||||
appearNote: Ref<misskey.entities.Note>;
|
note: Ref<misskey.entities.Note>;
|
||||||
|
isDeletedRef: Ref<boolean>;
|
||||||
}) {
|
}) {
|
||||||
const appearNote = props.appearNote;
|
const note = props.note;
|
||||||
const connection = $i ? stream : null;
|
const connection = $i ? stream : null;
|
||||||
|
|
||||||
function onStreamNoteUpdated(data): void {
|
function onStreamNoteUpdated(data): void {
|
||||||
const { type, id, body } = data;
|
const { type, id, body } = data;
|
||||||
|
|
||||||
if (id !== appearNote.value.id) return;
|
if (id !== note.value.id) return;
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'reacted': {
|
case 'reacted': {
|
||||||
const reaction = body.reaction;
|
const reaction = body.reaction;
|
||||||
|
|
||||||
if (body.emoji) {
|
if (body.emoji) {
|
||||||
const emojis = appearNote.value.emojis || [];
|
const emojis = note.value.emojis || [];
|
||||||
if (!emojis.includes(body.emoji)) {
|
if (!emojis.includes(body.emoji)) {
|
||||||
appearNote.value.emojis = [...emojis, body.emoji];
|
note.value.emojis = [...emojis, body.emoji];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: reactionsプロパティがない場合ってあったっけ? なければ || {} は消せる
|
// TODO: reactionsプロパティがない場合ってあったっけ? なければ || {} は消せる
|
||||||
const currentCount = (appearNote.value.reactions || {})[reaction] || 0;
|
const currentCount = (note.value.reactions || {})[reaction] || 0;
|
||||||
|
|
||||||
appearNote.value.reactions[reaction] = currentCount + 1;
|
note.value.reactions[reaction] = currentCount + 1;
|
||||||
|
|
||||||
if ($i && (body.userId === $i.id)) {
|
if ($i && (body.userId === $i.id)) {
|
||||||
appearNote.value.myReaction = reaction;
|
note.value.myReaction = reaction;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -41,12 +42,12 @@ export function useNoteCapture(props: {
|
|||||||
const reaction = body.reaction;
|
const reaction = body.reaction;
|
||||||
|
|
||||||
// TODO: reactionsプロパティがない場合ってあったっけ? なければ || {} は消せる
|
// TODO: reactionsプロパティがない場合ってあったっけ? なければ || {} は消せる
|
||||||
const currentCount = (appearNote.value.reactions || {})[reaction] || 0;
|
const currentCount = (note.value.reactions || {})[reaction] || 0;
|
||||||
|
|
||||||
appearNote.value.reactions[reaction] = Math.max(0, currentCount - 1);
|
note.value.reactions[reaction] = Math.max(0, currentCount - 1);
|
||||||
|
|
||||||
if ($i && (body.userId === $i.id)) {
|
if ($i && (body.userId === $i.id)) {
|
||||||
appearNote.value.myReaction = null;
|
note.value.myReaction = null;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -54,7 +55,7 @@ export function useNoteCapture(props: {
|
|||||||
case 'pollVoted': {
|
case 'pollVoted': {
|
||||||
const choice = body.choice;
|
const choice = body.choice;
|
||||||
|
|
||||||
const choices = [...appearNote.value.poll.choices];
|
const choices = [...note.value.poll.choices];
|
||||||
choices[choice] = {
|
choices[choice] = {
|
||||||
...choices[choice],
|
...choices[choice],
|
||||||
votes: choices[choice].votes + 1,
|
votes: choices[choice].votes + 1,
|
||||||
@ -63,12 +64,12 @@ export function useNoteCapture(props: {
|
|||||||
} : {})
|
} : {})
|
||||||
};
|
};
|
||||||
|
|
||||||
appearNote.value.poll.choices = choices;
|
note.value.poll.choices = choices;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'deleted': {
|
case 'deleted': {
|
||||||
appearNote.value.deletedAt = new Date();
|
props.isDeletedRef.value = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -77,7 +78,7 @@ export function useNoteCapture(props: {
|
|||||||
function capture(withHandler = false): void {
|
function capture(withHandler = false): void {
|
||||||
if (connection) {
|
if (connection) {
|
||||||
// TODO: このノートがストリーミング経由で流れてきた場合のみ sr する
|
// TODO: このノートがストリーミング経由で流れてきた場合のみ sr する
|
||||||
connection.send(document.body.contains(props.rootEl.value) ? 'sr' : 's', { id: appearNote.value.id });
|
connection.send(document.body.contains(props.rootEl.value) ? 'sr' : 's', { id: note.value.id });
|
||||||
if (withHandler) connection.on('noteUpdated', onStreamNoteUpdated);
|
if (withHandler) connection.on('noteUpdated', onStreamNoteUpdated);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -85,7 +86,7 @@ export function useNoteCapture(props: {
|
|||||||
function decapture(withHandler = false): void {
|
function decapture(withHandler = false): void {
|
||||||
if (connection) {
|
if (connection) {
|
||||||
connection.send('un', {
|
connection.send('un', {
|
||||||
id: appearNote.value.id,
|
id: note.value.id,
|
||||||
});
|
});
|
||||||
if (withHandler) connection.off('noteUpdated', onStreamNoteUpdated);
|
if (withHandler) connection.off('noteUpdated', onStreamNoteUpdated);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user