diff --git a/fe_calckey/frontend/client/src/components/MagNote.vue b/fe_calckey/frontend/client/src/components/MagNote.vue
index 66c6c54..93bf6c3 100644
--- a/fe_calckey/frontend/client/src/components/MagNote.vue
+++ b/fe_calckey/frontend/client/src/components/MagNote.vue
@@ -11,7 +11,7 @@
:class="{ renote: isRenote }"
:id="appearNote.id"
>
-
-
router.push(notePage(e))"
@focusfooter="footerEl.focus()"
@expanded="(e) => setPostExpanded(e)"
- >
+ >
@@ -229,14 +229,14 @@ import type { Ref } from "vue";
import { computed, inject, onMounted, ref, toRaw } from "vue";
import * as mfm from "mfm-js";
import type * as misskey from "calckey-js";
-import MkNoteSub from "@/components/MkNoteSub.vue";
-import MkSubNoteContent from "./MkSubNoteContent.vue";
-import XNoteHeader from "@/components/MkNoteHeader.vue";
-import XRenoteButton from "@/components/MkRenoteButton.vue";
+import XNoteSub from "@/components/MagNoteSub.vue";
+import XSubNoteContent from "./MagSubNoteContent.vue";
+import XNoteHeader from "@/components/MagNoteHeader.vue";
+import XRenoteButton from "@/components/MagRenoteButton.vue";
import XReactionsViewer from "@/components/MkReactionsViewer.vue";
import XStarButton from "@/components/MkStarButton.vue";
import XStarButtonNoEmoji from "@/components/MkStarButtonNoEmoji.vue";
-import XQuoteButton from "@/components/MkQuoteButton.vue";
+import XQuoteButton from "@/components/MagQuoteButton.vue";
import MkVisibility from "@/components/MkVisibility.vue";
import copyToClipboard from "@/scripts/copy-to-clipboard";
import { url } from "@/config";
@@ -298,13 +298,13 @@ if (noteViewInterruptors.length > 0) {
const isRenote = magIsRenote(note);
-const el = ref();
-const footerEl = ref();
-const menuButton = ref();
+const el = ref(null);
+const footerEl = ref(null);
+const menuButton = ref(null);
const starButton = ref>();
const renoteButton = ref>();
-const renoteTime = ref();
-const reactButton = ref();
+const renoteTime = ref(null);
+const reactButton = ref(null);
let appearNote = $computed(
() => magEffectiveNote(note) as packed.PackNoteMaybeFull
);
@@ -386,7 +386,7 @@ function onContextmenu(ev: MouseEvent): void {
return isLink(el.parentElement);
}
};
- if (isLink(ev.target)) return;
+ if (ev.target && isLink(ev.target as HTMLElement)) return;
if (window.getSelection()?.toString() !== "") return;
if (defaultStore.state.useReactionPickerForContextMenu) {
@@ -451,11 +451,11 @@ function menu(viaKeyboard = false): void {
note: note,
translating,
translation,
- menuButton,
+ menuButton: menuButton.value,
isDeleted,
- currentClipPage,
+ currentClipPage: currentClipPage?.value,
}),
- menuButton.value,
+ menuButton.value ?? undefined,
{
viaKeyboard,
}
@@ -478,7 +478,7 @@ function showRenoteMenu(viaKeyboard = false): void {
},
},
],
- renoteTime.value,
+ renoteTime.value ?? undefined,
{
viaKeyboard: viaKeyboard,
}
diff --git a/fe_calckey/frontend/client/src/components/MagNoteDetailed.vue b/fe_calckey/frontend/client/src/components/MagNoteDetailed.vue
index 56e1269..4da7c78 100644
--- a/fe_calckey/frontend/client/src/components/MagNoteDetailed.vue
+++ b/fe_calckey/frontend/client/src/components/MagNoteDetailed.vue
@@ -9,7 +9,7 @@
:tabindex="!isDeleted ? '-1' : null"
:class="{ renote: magIsRenote(note) }"
>
-
-
-
+ >
-
-
-
+
-
-
+
+
@@ -40,10 +43,18 @@
import { defineComponent } from "vue";
import XReactionsViewer from "@/components/MkReactionsViewer.vue";
import XMediaList from "@/components/MkMediaList.vue";
-import XPoll from "@/components/MkPoll.vue";
+import XPoll from "@/components/MagPoll.vue";
import * as os from "@/os";
+import { packed } from "magnetar-common";
+import { resolveNote } from "@/scripts-mag/mag-util";
+import { $i } from "@/account";
export default defineComponent({
+ computed: {
+ $i() {
+ return $i;
+ },
+ },
components: {
XReactionsViewer,
XMediaList,
@@ -52,14 +63,14 @@ export default defineComponent({
data() {
return {
- notes: [],
+ notes: [] as packed.PackNoteMaybeFull[],
isScrolling: false,
};
},
created() {
- os.api("notes/featured").then((notes) => {
- this.notes = notes;
+ os.api("notes/featured").then(async (notes) => {
+ this.notes = await Promise.all(notes.map(resolveNote));
});
},
diff --git a/fe_calckey/frontend/client/src/scripts-mag/mag-util.ts b/fe_calckey/frontend/client/src/scripts-mag/mag-util.ts
index 226ec91..1e2e38e 100644
--- a/fe_calckey/frontend/client/src/scripts-mag/mag-util.ts
+++ b/fe_calckey/frontend/client/src/scripts-mag/mag-util.ts
@@ -1,6 +1,7 @@
import * as Misskey from "calckey-js";
-import { packed, types } from "magnetar-common";
+import { endpoints, packed, types } from "magnetar-common";
import { UnicodeEmojiDef } from "@/scripts/emojilist";
+import * as os from "@/os";
// https://stackoverflow.com/a/50375286 Evil magic
type Dist
= U extends any ? (k: U) => void : never;
@@ -331,3 +332,10 @@ export function magReactionIndex(
return magReactionEquals(r, reactionType);
});
}
+
+export const resolveNote = async ({ id }: { id: string }) =>
+ os.magApi(
+ endpoints.GetNoteById,
+ { attachments: true, context: true },
+ { id }
+ );
diff --git a/fe_calckey/frontend/client/src/scripts/get-note-menu.ts b/fe_calckey/frontend/client/src/scripts/get-note-menu.ts
index 5fe1489..f68c56a 100644
--- a/fe_calckey/frontend/client/src/scripts/get-note-menu.ts
+++ b/fe_calckey/frontend/client/src/scripts/get-note-menu.ts
@@ -9,23 +9,18 @@ import { url } from "@/config";
import { noteActions } from "@/store";
import { shareAvailable } from "@/scripts/share-available";
import { getUserMenu } from "@/scripts/get-user-menu";
-import {
- magEffectiveNote,
- magTransMap,
- magTransProperty,
- magTransUsername,
-} from "@/scripts-mag/mag-util";
+import { magEffectiveNote, magTransUsername } from "@/scripts-mag/mag-util";
import { packed } from "magnetar-common";
export function getNoteMenu(props: {
- note: packed.PackNoteMaybeFull | misskey.entities.Note;
- menuButton: Ref;
+ note: packed.PackNoteMaybeFull;
+ menuButton: HTMLElement | null;
translation: Ref;
translating: Ref;
isDeleted: Ref;
- currentClipPage?: Ref;
+ currentClipPage?: misskey.entities.Clip;
}) {
- const appearNote = magEffectiveNote(props.note);
+ const appearNote = magEffectiveNote(props.note) as packed.PackNoteMaybeFull;
function del(): void {
os.confirm({
@@ -36,7 +31,7 @@ export function getNoteMenu(props: {
os.api("notes/delete", {
noteId: appearNote.id,
- });
+ }).then();
});
}
@@ -49,23 +44,23 @@ export function getNoteMenu(props: {
os.api("notes/delete", {
noteId: appearNote.id,
- });
+ }).then();
os.post({
initialNote: appearNote,
- renote: magTransProperty(appearNote, "renoted_note", "renote"),
- reply: magTransProperty(appearNote, "parent_note", "reply"),
- });
+ renote: appearNote.renoted_note,
+ reply: appearNote.parent_note,
+ }).then();
});
}
function edit(): void {
os.post({
initialNote: appearNote,
- renote: magTransProperty(appearNote, "renoted_note", "renote"),
- reply: magTransProperty(appearNote, "parent_note", "reply"),
+ renote: appearNote.renoted_note,
+ reply: appearNote.parent_note,
editId: appearNote.id,
- });
+ }).then();
}
function toggleFavorite(favorite: boolean): void {
@@ -74,7 +69,7 @@ export function getNoteMenu(props: {
{
noteId: appearNote.id,
}
- );
+ ).then();
}
function toggleWatch(watch: boolean): void {
@@ -83,7 +78,7 @@ export function getNoteMenu(props: {
{
noteId: appearNote.id,
}
- );
+ ).then();
}
function toggleThreadMute(mute: boolean): void {
@@ -92,22 +87,22 @@ export function getNoteMenu(props: {
{
noteId: appearNote.id,
}
- );
+ ).then();
}
function copyContent(): void {
copyToClipboard(appearNote.text);
- os.success();
+ os.success().then();
}
function copyLink(): void {
copyToClipboard(`${url}/notes/${appearNote.id}`);
- os.success();
+ os.success().then();
}
function copyOriginal(): void {
copyToClipboard(appearNote.url ?? appearNote.uri);
- os.success();
+ os.success().then();
}
function togglePin(pin: boolean): void {
@@ -122,7 +117,7 @@ export function getNoteMenu(props: {
os.alert({
type: "error",
text: i18n.ts.pinLimitExceeded,
- });
+ }).then();
}
});
}
@@ -162,14 +157,15 @@ export function getNoteMenu(props: {
result
);
- os.apiWithDialog("clips/add-note", {
- clipId: clip.id,
- noteId: appearNote.id,
- });
+ if (clip)
+ os.apiWithDialog("clips/add-note", {
+ clipId: clip.id,
+ noteId: appearNote.id,
+ }).then();
},
},
null,
- ...clips.map((clip) => ({
+ ...clips?.map((clip) => ({
text: clip.name,
action: () => {
os.promiseDialog(
@@ -196,9 +192,9 @@ export function getNoteMenu(props: {
os.apiWithDialog("clips/remove-note", {
clipId: clip.id,
noteId: appearNote.id,
- });
+ }).then();
if (
- props.currentClipPage?.value.id ===
+ props.currentClipPage?.id ===
clip.id
)
props.isDeleted.value = true;
@@ -207,34 +203,36 @@ export function getNoteMenu(props: {
os.alert({
type: "error",
text: err.message + "\n" + err.id,
- });
+ }).then();
}
}
);
},
})),
],
- props.menuButton.value,
+ props.menuButton ?? undefined,
{}
).then(focus);
}
async function unclip(): Promise {
os.apiWithDialog("clips/remove-note", {
- clipId: props.currentClipPage.value.id,
+ clipId: props.currentClipPage?.id,
noteId: appearNote.id,
- });
+ }).then();
props.isDeleted.value = true;
}
function share(): void {
- navigator.share({
- title: i18n.t("noteOf", {
- user: magTransUsername(appearNote.user),
- }),
- text: appearNote.text ?? undefined,
- url: `${url}/notes/${appearNote.id}`,
- });
+ navigator
+ .share({
+ title: i18n.t("noteOf", {
+ user: magTransUsername(appearNote.user),
+ }),
+ text: appearNote.text ?? undefined,
+ url: `${url}/notes/${appearNote.id}`,
+ })
+ .then();
}
async function translate(): Promise {
@@ -254,12 +252,11 @@ export function getNoteMenu(props: {
noteId: appearNote.id,
});
- const isAppearAuthor =
- magTransMap(appearNote, "user", "userId", (u) => u.id) === $i.id;
+ const isAppearAuthor = appearNote.user.id === $i.id;
const isModerator = $i.isAdmin || $i.isModerator;
menu = [
- ...(props.currentClipPage?.value.userId === $i.id
+ ...(props.currentClipPage?.value?.userId === $i.id
? [
{
icon: "ph-minus-circle ph-bold ph-lg",
@@ -412,7 +409,7 @@ export function getNoteMenu(props: {
},
{},
"closed"
- );
+ ).then();
},
}
: undefined,
diff --git a/fe_calckey/frontend/client/src/scripts/get-user-menu.ts b/fe_calckey/frontend/client/src/scripts/get-user-menu.ts
index c2c9189..4ab994d 100644
--- a/fe_calckey/frontend/client/src/scripts/get-user-menu.ts
+++ b/fe_calckey/frontend/client/src/scripts/get-user-menu.ts
@@ -1,4 +1,3 @@
-import * as Acct from "calckey-js/built/acct";
import { defineAsyncComponent } from "vue";
import { i18n } from "@/i18n";
import copyToClipboard from "@/scripts/copy-to-clipboard";
@@ -8,8 +7,14 @@ import { userActions } from "@/store";
import { $i, iAmModerator } from "@/account";
import { mainRouter } from "@/router";
import { Router } from "@/nirax";
+import * as Misskey from "calckey-js";
+import { packed } from "magnetar-common";
+import { magTransProperty } from "@/scripts-mag/mag-util";
-export function getUserMenu(user, router: Router = mainRouter) {
+export function getUserMenu(
+ user: packed.PackUserMaybeAll | Misskey.entities.UserDetailed,
+ router: Router = mainRouter
+) {
const meId = $i ? $i.id : null;
async function pushList() {
@@ -60,11 +65,12 @@ export function getUserMenu(user, router: Router = mainRouter) {
}
async function toggleMute() {
- if (user.isMuted) {
+ if (magTransProperty(user, "mute", "isMuted")) {
os.apiWithDialog("mute/delete", {
userId: user.id,
}).then(() => {
- user.isMuted = false;
+ if ("isMuted" in user) user.isMuted = false;
+ else if ("mute" in user) user.mute = false;
});
} else {
const { canceled, result: period } = await os.select({
@@ -112,82 +118,121 @@ export function getUserMenu(user, router: Router = mainRouter) {
userId: user.id,
expiresAt,
}).then(() => {
- user.isMuted = true;
+ if ("isMuted" in user) user.isMuted = true;
+ else if ("mute" in user) user.mute = true;
});
}
}
async function toggleRenoteMute(): Promise {
os.apiWithDialog(
- user.isRenoteMuted ? "renote-mute/delete" : "renote-mute/create",
+ magTransProperty(user, "mute_renotes", "isRenoteMuted")
+ ? "renote-mute/delete"
+ : "renote-mute/create",
{
userId: user.id,
}
).then(() => {
- user.isRenoteMuted = !user.isRenoteMuted;
+ if ("isRenoteMuted" in user)
+ user.isRenoteMuted = !user.isRenoteMuted;
+ else if ("mute_renotes" in user)
+ user.mute_renotes = !user.mute_renotes;
});
}
async function toggleBlock(): Promise {
if (
!(await getConfirmed(
- user.isBlocking ? i18n.ts.unblockConfirm : i18n.ts.blockConfirm
+ magTransProperty(user, "you_block", "isBlocking")
+ ? i18n.ts.unblockConfirm
+ : i18n.ts.blockConfirm
))
)
return;
await os.apiWithDialog(
- user.isBlocking ? "blocking/delete" : "blocking/create",
+ magTransProperty(user, "you_block", "isBlocking")
+ ? "blocking/delete"
+ : "blocking/create",
{
userId: user.id,
}
);
- user.isBlocking = !user.isBlocking;
- await os.api(user.isBlocking ? "mute/create" : "mute/delete", {
- userId: user.id,
- });
- user.isMuted = user.isBlocking;
- if (user.isBlocking) {
+
+ if ("isBlocking" in user) user.isBlocking = !user.isBlocking;
+ else if ("you_block" in user) user.you_block = !user.you_block;
+
+ await os.api(
+ magTransProperty(user, "you_block", "isBlocking")
+ ? "mute/create"
+ : "mute/delete",
+ {
+ userId: user.id,
+ }
+ );
+
+ if ("isMuted" in user) user.isMuted = user.isBlocking;
+ else if ("mute" in user) user.mute = !user.mute;
+
+ if (magTransProperty(user, "isBlocking", "you_block")) {
await os.api("following/delete", {
userId: user.id,
});
- user.isFollowing = false;
+
+ if ("isFollowing" in user) user.isFollowing = false;
+ else if ("you_follow" in user) user.you_follow = false;
}
}
async function toggleSilence() {
if (
!(await getConfirmed(
- i18n.t(user.isSilenced ? "unsilenceConfirm" : "silenceConfirm")
+ i18n.t(
+ magTransProperty(user, "is_silenced", "isSilenced")
+ ? "unsilenceConfirm"
+ : "silenceConfirm"
+ )
))
)
return;
os.apiWithDialog(
- user.isSilenced ? "admin/unsilence-user" : "admin/silence-user",
+ magTransProperty(user, "isSilenced", "is_silenced")
+ ? "admin/unsilence-user"
+ : "admin/silence-user",
{
userId: user.id,
}
).then(() => {
- user.isSilenced = !user.isSilenced;
+ if ("isSilenced" in user) user.isSilenced = !user.isSilenced;
+ else if ("is_silenced" in user)
+ user.is_silenced = !user.is_silenced;
});
}
async function toggleSuspend() {
if (
!(await getConfirmed(
- i18n.t(user.isSuspended ? "unsuspendConfirm" : "suspendConfirm")
+ i18n.t(
+ magTransProperty(user, "is_suspended", "isSuspended")
+ ? "unsuspendConfirm"
+ : "suspendConfirm"
+ )
))
)
return;
os.apiWithDialog(
- user.isSuspended ? "admin/unsuspend-user" : "admin/suspend-user",
+ magTransProperty(user, "is_suspended", "isSuspended")
+ ? "admin/unsuspend-user"
+ : "admin/suspend-user",
{
userId: user.id,
}
).then(() => {
- user.isSuspended = !user.isSuspended;
+ if ("isSuspended" in user) user.isSuspended = !user.isSuspended;
+ else if ("is_suspended" in user)
+ user.is_suspended = !user.is_suspended;
});
}
@@ -220,7 +265,9 @@ export function getUserMenu(user, router: Router = mainRouter) {
os.apiWithDialog("following/invalidate", {
userId: user.id,
}).then(() => {
- user.isFollowed = !user.isFollowed;
+ if ("isFollowed" in user) user.isFollowed = !user.isFollowed;
+ else if ("follows_you" in user)
+ user.follows_you = !user.follows_you;
});
}
@@ -266,10 +313,10 @@ export function getUserMenu(user, router: Router = mainRouter) {
: undefined,
null,
{
- icon: user.isRenoteMuted
+ icon: magTransProperty(user, "mute_renotes", "isRenoteMuted")
? "ph-eye ph-bold ph-lg"
: "ph-eye-slash ph-bold ph-lg",
- text: user.isRenoteMuted
+ text: magTransProperty(user, "mute_renotes", "isRenoteMuted")
? i18n.ts.renoteUnmute
: i18n.ts.renoteMute,
action: toggleRenoteMute,
@@ -279,21 +326,26 @@ export function getUserMenu(user, router: Router = mainRouter) {
if ($i && meId !== user.id) {
menu = menu.concat([
{
- icon: user.isMuted
+ icon: magTransProperty(user, "mute", "isMuted")
? "ph-eye ph-bold ph-lg"
: "ph-eye-slash ph-bold ph-lg",
- text: user.isMuted ? i18n.ts.unmute : i18n.ts.mute,
- hidden: user.isBlocking === true,
+ text: magTransProperty(user, "mute", "isMuted")
+ ? i18n.ts.unmute
+ : i18n.ts.mute,
+ hidden:
+ magTransProperty(user, "you_block", "isBlocking") === true,
action: toggleMute,
},
{
icon: "ph-prohibit ph-bold ph-lg",
- text: user.isBlocking ? i18n.ts.unblock : i18n.ts.block,
+ text: magTransProperty(user, "you_block", "isBlocking")
+ ? i18n.ts.unblock
+ : i18n.ts.block,
action: toggleBlock,
},
]);
- if (user.isFollowed) {
+ if (magTransProperty(user, "follows_you", "isFollowed")) {
menu = menu.concat([
{
icon: "ph-link-break ph-bold ph-lg",
@@ -317,12 +369,14 @@ export function getUserMenu(user, router: Router = mainRouter) {
null,
{
icon: "ph-microphone-slash ph-bold ph-lg",
- text: user.isSilenced ? i18n.ts.unsilence : i18n.ts.silence,
+ text: magTransProperty(user, "is_silenced", "isSilenced")
+ ? i18n.ts.unsilence
+ : i18n.ts.silence,
action: toggleSilence,
},
{
icon: "ph-snowflake ph-bold ph-lg",
- text: user.isSuspended
+ text: magTransProperty(user, "is_suspended", "isSuspended")
? i18n.ts.unsuspend
: i18n.ts.suspend,
action: toggleSuspend,
diff --git a/fe_calckey/frontend/client/src/scripts/page-metadata.ts b/fe_calckey/frontend/client/src/scripts/page-metadata.ts
index debd54f..39335f7 100644
--- a/fe_calckey/frontend/client/src/scripts/page-metadata.ts
+++ b/fe_calckey/frontend/client/src/scripts/page-metadata.ts
@@ -19,7 +19,7 @@ export type PageMetadata = {
subtitle?: string;
icon?: string | null;
avatar?: packed.PackUserBase | misskey.entities.User | null;
- userName?: misskey.entities.User | null;
+ userName?: packed.PackUserBase | misskey.entities.User | null;
bg?: string;
};
diff --git a/fe_calckey/frontend/client/src/scripts/reaction-picker.ts b/fe_calckey/frontend/client/src/scripts/reaction-picker.ts
index 0f657b4..6bdf0fa 100644
--- a/fe_calckey/frontend/client/src/scripts/reaction-picker.ts
+++ b/fe_calckey/frontend/client/src/scripts/reaction-picker.ts
@@ -38,7 +38,7 @@ class ReactionPicker {
}
public show(
- src: HTMLElement,
+ src: HTMLElement | null,
onChosen: ReactionPicker["onChosen"],
onClosed: ReactionPicker["onClosed"]
) {
diff --git a/fe_calckey/frontend/client/src/scripts/use-note-capture.ts b/fe_calckey/frontend/client/src/scripts/use-note-capture.ts
index 535ff2c..e387928 100644
--- a/fe_calckey/frontend/client/src/scripts/use-note-capture.ts
+++ b/fe_calckey/frontend/client/src/scripts/use-note-capture.ts
@@ -1,18 +1,13 @@
import { onUnmounted, Ref, toRaw } from "vue";
-import * as misskey from "calckey-js";
import { stream } from "@/stream";
import { $i } from "@/account";
import * as os from "@/os";
import { endpoints, packed } from "magnetar-common";
-import {
- magConvertReaction,
- magReactionIndex,
- noteIsMag,
-} from "@/scripts-mag/mag-util";
+import { magConvertReaction, magReactionIndex } from "@/scripts-mag/mag-util";
export function useNoteCapture(props: {
rootEl: Ref;
- note: Ref;
+ note: Ref;
isDeletedRef: Ref;
}) {
const note = props.note;
@@ -23,180 +18,98 @@ export function useNoteCapture(props: {
if (id !== note.value.id) return;
- if (noteIsMag(note.value)) {
- switch (type) {
- case "reacted": {
- const reaction = body.reaction as string;
+ switch (type) {
+ case "reacted": {
+ const reaction = body.reaction as string;
- const reactionType = magConvertReaction(
+ const reactionType = magConvertReaction(
+ reaction,
+ body?.emoji?.url
+ );
+ const foundReaction = magReactionIndex(
+ note.value.reactions,
+ reactionType
+ );
+
+ const selfReact = ($i && body.userId === $i.id) || false;
+ if (foundReaction >= 0) {
+ const [reaction, cnt, selfReactPrev] = toRaw(
+ note.value.reactions[foundReaction]
+ );
+ note.value.reactions[foundReaction] = [
reaction,
- body?.emoji?.url
- );
- const foundReaction = magReactionIndex(
- note.value.reactions,
- reactionType
- );
-
- const selfReact = ($i && body.userId === $i.id) || false;
- if (foundReaction >= 0) {
- const [reaction, cnt, selfReactPrev] = toRaw(
- note.value.reactions[foundReaction]
- );
- note.value.reactions[foundReaction] = [
- reaction,
- cnt + 1,
- selfReactPrev || selfReact,
- ];
- } else {
- note.value.reactions.push([reactionType, 1, selfReact]);
- }
- break;
- }
-
- case "unreacted": {
- const reaction = body.reaction;
-
- const reactionType = magConvertReaction(reaction);
- const foundReaction = magReactionIndex(
- note.value.reactions,
- reactionType
- );
-
- const selfUnReact = ($i && body.userId === $i.id) || false;
- if (foundReaction >= 0) {
- const [name, cnt, selfReact] =
- note.value.reactions[foundReaction];
-
- note.value.reactions[foundReaction] = [
- name,
- Math.max(0, cnt - 1),
- !selfUnReact && (selfReact ?? false),
- ];
- }
-
- break;
- }
-
- case "pollVoted": {
- const choice = body.choice;
-
- if (note.value.poll) {
- const options = [...note.value.poll.options];
- options[choice] = {
- ...options[choice],
- votes_count: options[choice].votes_count + 1,
- voted: ($i && body.userId === $i.id) || null,
- };
- note.value.poll.options = options;
- }
-
- break;
- }
-
- case "deleted": {
- props.isDeletedRef.value = true;
- break;
- }
-
- case "updated": {
- const editedNote = await os.magApi(
- endpoints.GetNoteById,
- {
- attachments: true,
- context: true,
- },
- { id }
- );
-
- const keys = new Set();
- Object.keys(editedNote)
- .concat(Object.keys(note.value))
- .forEach((key) => keys.add(key));
- keys.forEach((key) => {
- note.value[key] = editedNote[key];
- });
- break;
+ cnt + 1,
+ selfReactPrev || selfReact,
+ ];
+ } else {
+ note.value.reactions.push([reactionType, 1, selfReact]);
}
+ break;
}
- } else {
- switch (type) {
- case "reacted": {
- const reaction = body.reaction;
- if (body.emoji) {
- const emojis = note.value.emojis || [];
- if (!emojis.includes(body.emoji)) {
- note.value.emojis = [...emojis, body.emoji];
- }
- }
+ case "unreacted": {
+ const reaction = body.reaction;
- // TODO: reactionsプロパティがない場合ってあったっけ? なければ || {} は消せる
- const currentCount = note.value.reactions?.[reaction] || 0;
+ const reactionType = magConvertReaction(reaction);
+ const foundReaction = magReactionIndex(
+ note.value.reactions,
+ reactionType
+ );
- note.value.reactions[reaction] = currentCount + 1;
+ const selfUnReact = ($i && body.userId === $i.id) || false;
+ if (foundReaction >= 0) {
+ const [name, cnt, selfReact] =
+ note.value.reactions[foundReaction];
- if ($i && body.userId === $i.id) {
- note.value.myReaction = reaction;
- }
- break;
+ note.value.reactions[foundReaction] = [
+ name,
+ Math.max(0, cnt - 1),
+ !selfUnReact && (selfReact ?? false),
+ ];
}
- case "unreacted": {
- const reaction = body.reaction;
+ break;
+ }
- // TODO: reactionsプロパティがない場合ってあったっけ? なければ || {} は消せる
- const currentCount = note.value.reactions?.[reaction] || 0;
+ case "pollVoted": {
+ const choice = body.choice;
- note.value.reactions[reaction] = Math.max(
- 0,
- currentCount - 1
- );
-
- if ($i && body.userId === $i.id) {
- note.value.myReaction = undefined;
- }
- break;
+ if (note.value.poll) {
+ const options = [...note.value.poll.options];
+ options[choice] = {
+ ...options[choice],
+ votes_count: options[choice].votes_count + 1,
+ voted: ($i && body.userId === $i.id) || null,
+ };
+ note.value.poll.options = options;
}
- case "pollVoted": {
- const choice = body.choice;
+ break;
+ }
- if (note.value.poll) {
- const choices = [...note.value.poll.choices];
- choices[choice] = {
- ...choices[choice],
- votes: choices[choice].votes + 1,
- ...($i && body.userId === $i.id
- ? {
- isVoted: true,
- }
- : {}),
- };
- note.value.poll.choices = choices;
- }
+ case "deleted": {
+ props.isDeletedRef.value = true;
+ break;
+ }
- break;
- }
+ case "updated": {
+ const editedNote = await os.magApi(
+ endpoints.GetNoteById,
+ {
+ attachments: true,
+ context: true,
+ },
+ { id }
+ );
- case "deleted": {
- props.isDeletedRef.value = true;
- break;
- }
-
- case "updated": {
- const editedNote = await os.api("notes/show", {
- noteId: id,
- });
-
- const keys = new Set();
- Object.keys(editedNote)
- .concat(Object.keys(note.value))
- .forEach((key) => keys.add(key));
- keys.forEach((key) => {
- note.value[key] = editedNote[key];
- });
- break;
- }
+ const keys = new Set();
+ Object.keys(editedNote)
+ .concat(Object.keys(note.value))
+ .forEach((key) => keys.add(key));
+ keys.forEach((key) => {
+ note.value[key] = editedNote[key];
+ });
+ break;
}
}
}
diff --git a/fe_calckey/frontend/magnetar-common/src/types.ts b/fe_calckey/frontend/magnetar-common/src/types.ts
index 6692a64..4a2340d 100644
--- a/fe_calckey/frontend/magnetar-common/src/types.ts
+++ b/fe_calckey/frontend/magnetar-common/src/types.ts
@@ -41,3 +41,4 @@ export { DriveFolderBase } from "./types/DriveFolderBase";
export { DriveFolderParentExt } from "./types/DriveFolderParentExt";
export { ImageMeta } from "./types/ImageMeta";
export { InstanceTicker } from "./types/InstanceTicker";
+export { MovedTo } from "./types/MovedTo";
diff --git a/fe_calckey/frontend/magnetar-common/src/types/MovedTo.ts b/fe_calckey/frontend/magnetar-common/src/types/MovedTo.ts
new file mode 100644
index 0000000..1f1d60f
--- /dev/null
+++ b/fe_calckey/frontend/magnetar-common/src/types/MovedTo.ts
@@ -0,0 +1,3 @@
+// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
+
+export interface MovedTo { moved_to_uri: string, username: string, host: string, }
\ No newline at end of file
diff --git a/fe_calckey/frontend/magnetar-common/src/types/UserProfileExt.ts b/fe_calckey/frontend/magnetar-common/src/types/UserProfileExt.ts
index 52080d7..784d137 100644
--- a/fe_calckey/frontend/magnetar-common/src/types/UserProfileExt.ts
+++ b/fe_calckey/frontend/magnetar-common/src/types/UserProfileExt.ts
@@ -1,5 +1,6 @@
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
import type { MmXml } from "./MmXml";
+import type { MovedTo } from "./MovedTo";
import type { ProfileField } from "./ProfileField";
-export interface UserProfileExt { is_locked: boolean, is_silenced: boolean, is_suspended: boolean, description: string | null, description_mm: MmXml | null, location: string | null, birthday: string | null, fields: Array, follower_count: number | null, following_count: number | null, note_count: number | null, url: string | null, moved_to_uri: string | null, also_known_as: string | null, banner_url: string | null, banner_blurhash: string | null, has_public_reactions: boolean, }
\ No newline at end of file
+export interface UserProfileExt { is_locked: boolean, is_silenced: boolean, is_suspended: boolean, description: string | null, description_mm: MmXml | null, location: string | null, birthday: string | null, fields: Array, follower_count: number | null, following_count: number | null, note_count: number | null, url: string | null, moved_to: MovedTo | null, also_known_as: string | null, banner_url: string | null, banner_blurhash: string | null, has_public_reactions: boolean, }
\ No newline at end of file
diff --git a/magnetar_sdk/src/types/user.rs b/magnetar_sdk/src/types/user.rs
index 9a647ec..c6fdc9b 100644
--- a/magnetar_sdk/src/types/user.rs
+++ b/magnetar_sdk/src/types/user.rs
@@ -56,6 +56,14 @@ pub struct UserBase {
pack!(PackUserBase, Required as id & Required as user);
+#[derive(Clone, Debug, Deserialize, Serialize, TS)]
+#[ts(export)]
+pub struct MovedTo {
+ pub moved_to_uri: String,
+ pub username: String,
+ pub host: String,
+}
+
#[derive(Clone, Debug, Deserialize, Serialize, TS)]
#[ts(export)]
pub struct UserProfileExt {
@@ -75,7 +83,7 @@ pub struct UserProfileExt {
pub url: Option,
- pub moved_to_uri: Option,
+ pub moved_to: Option,
pub also_known_as: Option,
pub banner_url: Option,
diff --git a/src/model/data/user.rs b/src/model/data/user.rs
index d3a21ff..e1070c6 100644
--- a/src/model/data/user.rs
+++ b/src/model/data/user.rs
@@ -5,7 +5,7 @@ use magnetar_sdk::types::emoji::{EmojiContext, PackEmojiBase};
use magnetar_sdk::types::instance::InstanceTicker;
use magnetar_sdk::types::note::PackNoteMaybeFull;
use magnetar_sdk::types::user::{
- AvatarDecoration, PackSecurityKeyBase, ProfileField, SecurityKeyBase, SpeechTransform,
+ AvatarDecoration, MovedTo, PackSecurityKeyBase, ProfileField, SecurityKeyBase, SpeechTransform,
UserAuthOverviewExt, UserBase, UserDetailExt, UserProfileExt, UserProfilePinsEx,
UserRelationExt, UserSecretsExt,
};
@@ -80,6 +80,7 @@ pub struct UserProfileExtSource<'a> {
pub banner: Option<&'a PackDriveFileBase>,
pub description_mm: Option<&'a MmXml>,
pub relation: Option<&'a UserRelationExt>,
+ pub moved_to: Option<&'a MovedTo>,
}
impl PackType> for UserProfileExt {
@@ -92,6 +93,7 @@ impl PackType> for UserProfileExt {
banner,
description_mm,
relation,
+ moved_to,
}: UserProfileExtSource,
) -> Self {
let follow_visibility = match profile.ff_visibility {
@@ -118,7 +120,7 @@ impl PackType> for UserProfileExt {
following_count: follow_visibility.then_some(user.following_count as usize),
note_count: Some(user.notes_count as usize),
url: profile.url.clone(),
- moved_to_uri: user.moved_to_uri.clone(),
+ moved_to: moved_to.cloned(),
also_known_as: user.also_known_as.clone(),
banner_url: banner.and_then(|b| b.file.0.url.to_owned()),
banner_blurhash: banner.and_then(|b| b.file.0.blurhash.clone()),
diff --git a/src/model/processing/user.rs b/src/model/processing/user.rs
index 4df5536..7d9e748 100644
--- a/src/model/processing/user.rs
+++ b/src/model/processing/user.rs
@@ -13,8 +13,8 @@ use magnetar_sdk::types::drive::PackDriveFileBase;
use magnetar_sdk::types::emoji::EmojiContext;
use magnetar_sdk::types::instance::InstanceTicker;
use magnetar_sdk::types::user::{
- PackSecurityKeyBase, PackUserBase, PackUserMaybeAll, PackUserSelfMaybeAll, ProfileField,
- SecurityKeyBase, UserAuthOverviewExt, UserBase, UserDetailExt, UserProfileExt,
+ MovedTo, PackSecurityKeyBase, PackUserBase, PackUserMaybeAll, PackUserSelfMaybeAll,
+ ProfileField, SecurityKeyBase, UserAuthOverviewExt, UserBase, UserDetailExt, UserProfileExt,
UserProfilePinsEx, UserRelationExt, UserSecretsExt,
};
use magnetar_sdk::types::{Id, MmXml};
@@ -153,6 +153,27 @@ impl UserModel {
_ => None,
};
+ let moved = match &user.moved_to_uri {
+ Some(uri) => {
+ let moved = ctx.service.db.get_user_by_uri(uri).await?;
+
+ moved.and_then(|m| {
+ let Some(uri) = m.uri else {
+ return None;
+ };
+
+ Some(MovedTo {
+ moved_to_uri: uri,
+ username: m.username,
+ host: m
+ .host
+ .unwrap_or_else(|| ctx.service.config.networking.host.to_string()),
+ })
+ })
+ }
+ None => None,
+ };
+
let description_mm = self.tokenize_description(&profile);
let fields = Vec::::deserialize(&profile.fields)?;
@@ -192,6 +213,7 @@ impl UserModel {
.and_then(|desc_mm| mmm::to_xml_string(&desc_mm).map(MmXml).ok())
.as_ref(),
relation,
+ moved_to: moved.as_ref(),
},
))
}