diff --git a/src/client/components/post-form.vue b/src/client/components/post-form.vue index d2c0cffa12..76919b468e 100644 --- a/src/client/components/post-form.vue +++ b/src/client/components/post-form.vue @@ -104,11 +104,19 @@ export default defineComponent({ type: String, required: false }, + initialVisibility: { + type: String, + required: false + }, + initialFiles: { + type: Array, + required: false + }, initialNote: { type: Object, required: false }, - instant: { + share: { type: Boolean, required: false, default: false @@ -136,7 +144,7 @@ export default defineComponent({ useCw: false, cw: null, localOnly: this.$store.state.rememberNoteVisibility ? this.$store.state.localOnly : this.$store.state.defaultNoteLocalOnly, - visibility: this.$store.state.rememberNoteVisibility ? this.$store.state.visibility : this.$store.state.defaultNoteVisibility, + visibility: (this.$store.state.rememberNoteVisibility ? this.$store.state.visibility : this.$store.state.defaultNoteVisibility) as typeof noteVisibilities[number], visibleUsers: [], autocomplete: null, draghover: false, @@ -212,6 +220,14 @@ export default defineComponent({ this.text = this.initialText; } + if (this.initialVisibility) { + this.visibility = this.initialVisibility; + } + + if (this.initialFiles) { + this.files = this.initialFiles; + } + if (this.mention) { this.text = this.mention.host ? `@${this.mention.username}@${toASCII(this.mention.host)}` : `@${this.mention.username}`; this.text += ' '; @@ -286,7 +302,7 @@ export default defineComponent({ this.$nextTick(() => { // 書きかけの投稿を復元 - if (!this.instant && !this.mention && !this.specified) { + if (!this.share && !this.mention && !this.specified) { const draft = JSON.parse(localStorage.getItem('drafts') || '{}')[this.draftKey]; if (draft) { this.text = draft.data.text; @@ -514,8 +530,6 @@ export default defineComponent({ }, saveDraft() { - if (this.instant) return; - const data = JSON.parse(localStorage.getItem('drafts') || '{}'); data[this.draftKey] = { diff --git a/src/client/pages/share.vue b/src/client/pages/share.vue index 7912e5421f..fe4e482752 100644 --- a/src/client/pages/share.vue +++ b/src/client/pages/share.vue @@ -3,10 +3,21 @@
{{ title }}
- - {{ $ts.close }} + + {{ $ts.close }}
-
@@ -17,6 +28,7 @@ import { faShareAlt } from '@fortawesome/free-solid-svg-icons'; import MkButton from '@/components/ui/button.vue'; import XPostForm from '@/components/post-form.vue'; import * as os from '@/os'; +import { noteVisibilities } from '../../types'; export default defineComponent({ components: { @@ -30,27 +42,88 @@ export default defineComponent({ title: this.$ts.share, icon: faShareAlt }, - title: null, - text: null, - url: null, - initialText: null, - posted: false, + state: 'fetching' as 'fetching' | 'writing' | 'posted', + + title: null as string | null, + initialText: null as string | null, + reply: null as any, + renote: null as any, + specified: null as any, + visibility: null as string | null, + files: null as any[] | null, faShareAlt } }, - created() { + async created() { const urlParams = new URLSearchParams(window.location.search); + this.title = urlParams.get('title'); - this.text = urlParams.get('text'); - this.url = urlParams.get('url'); - - let text = ''; - if (this.title) text += `【${this.title}】\n`; - if (this.text) text += `${this.text}\n`; - if (this.url) text += `${this.url}`; - this.initialText = text.trim(); + const text = urlParams.get('text'); + const url = urlParams.get('url'); + + let noteText = ''; + if (this.title) noteText += `【${this.title}】\n`; + // titleとtext(またはtext. Googleニュースがこれを吐く)が同一であればtextを省略 + if (text && this.title !== text && this.title !== `${text}.`) noteText += `${text}\n`; + if (url) noteText += `${url}`; + this.initialText = noteText.trim(); + + this.visibility = urlParams.get('visibility'); + if (!noteVisibilities.includes(this.visibility)) this.visibility = null; + + await Promise.all([(async () => { + const replyId = urlParams.get('replyId'); + const replyUri = urlParams.get('replyUri'); + if (replyId) { + this.reply = await os.api('notes/show', { + noteId: replyId + }); + } else if (replyUri) { + const obj = await os.api('ap/show', { + uri: replyUri + }) as any; + if (obj.type === 'Note') { + this.reply = obj.object; + } + } + })(),(async () => { + const renoteId = urlParams.get('replyId'); + const renoteUri = urlParams.get('replyUri'); + if (renoteId) { + this.renote = await os.api('notes/show', { + noteId: renoteId + }); + } else if (renoteUri) { + const obj = await os.api('ap/show', { + uri: renoteUri + }) as any; + if (obj.type === 'Note') { + this.renote = obj.object; + } + } + })(),(async () => { + const specifiedId = urlParams.get('specifiedId'); + const specifiedUsername = urlParams.get('specifiedUsername'); + if (specifiedId) { + this.specified = await os.api('users/show', { + userId: specifiedId + }); + } else if (specifiedUsername) { + this.specified = await os.api('users/show', { + username: specifiedUsername + }); + } + })(),(async () => { + const fileIds = urlParams.get('fileIds'); + if (fileIds) { + const promises = Promise.all(fileIds.split(',').map(fileId => os.api('drive/files/show', { fileId }))); + promises.then(files => this.files = files).catch(() => console.error('invalid fileIds')); + } + })(),]); + + this.state = 'writing'; }, methods: { diff --git a/src/client/scripts/initialize-sw.ts b/src/client/scripts/initialize-sw.ts index d6dbd5dbd4..abbfe4f4e2 100644 --- a/src/client/scripts/initialize-sw.ts +++ b/src/client/scripts/initialize-sw.ts @@ -17,7 +17,7 @@ export async function initializeSw() { }); // SEE: https://developer.mozilla.org/en-US/docs/Web/API/PushManager/subscribe#Parameters registration.pushManager.subscribe({ - userVisibleOnly: true, + userVisibleOnly: false, applicationServerKey: urlBase64ToUint8Array(instance.swPublickey) }).then(subscription => { function encode(buffer: ArrayBuffer | null) { diff --git a/src/client/sw/create-notification.ts b/src/client/sw/create-notification.ts index 2935eb100c..9382b88345 100644 --- a/src/client/sw/create-notification.ts +++ b/src/client/sw/create-notification.ts @@ -46,54 +46,63 @@ async function composeNotification(data: pushNotificationData): Promise<[string, case 'reply': return [t('_notification.youGotReply', { name: getUserName(data.body.user) }), { body: getNoteSummary(data.body.note, i18n.locale), - icon: data.body.user.avatarUrl + icon: data.body.user.avatarUrl, + data, }]; case 'renote': return [t('_notification.youRenoted', { name: getUserName(data.body.user) }), { body: getNoteSummary(data.body.note, i18n.locale), - icon: data.body.user.avatarUrl + icon: data.body.user.avatarUrl, + data, }]; case 'quote': return [t('_notification.youGotQuote', { name: getUserName(data.body.user) }), { body: getNoteSummary(data.body.note, i18n.locale), - icon: data.body.user.avatarUrl + icon: data.body.user.avatarUrl, + data, }]; case 'reaction': return [`${data.body.reaction} ${getUserName(data.body.user)}`, { body: getNoteSummary(data.body.note, i18n.locale), - icon: data.body.user.avatarUrl + icon: data.body.user.avatarUrl, + data, }]; case 'pollVote': return [t('_notification.youGotPoll', { name: getUserName(data.body.user) }), { body: getNoteSummary(data.body.note, i18n.locale), - icon: data.body.user.avatarUrl + icon: data.body.user.avatarUrl, + data, }]; case 'follow': return [t('_notification.youWereFollowed'), { body: getUserName(data.body.user), - icon: data.body.user.avatarUrl + icon: data.body.user.avatarUrl, + data, }]; case 'receiveFollowRequest': return [t('_notification.youReceivedFollowRequest'), { body: getUserName(data.body.user), - icon: data.body.user.avatarUrl + icon: data.body.user.avatarUrl, + data, }]; case 'followRequestAccepted': return [t('_notification.yourFollowRequestAccepted'), { body: getUserName(data.body.user), - icon: data.body.user.avatarUrl + icon: data.body.user.avatarUrl, + data, }]; case 'groupInvited': return [t('_notification.youWereInvitedToGroup'), { - body: data.body.group.name + body: data.body.group.name, + data, }]; default: @@ -103,12 +112,14 @@ async function composeNotification(data: pushNotificationData): Promise<[string, if (data.body.groupId === null) { return [t('_notification.youGotMessagingMessageFromUser', { name: getUserName(data.body.user) }), { icon: data.body.user.avatarUrl, - tag: `messaging:user:${data.body.user.id}` + tag: `messaging:user:${data.body.user.id}`, + data, }]; } return [t('_notification.youGotMessagingMessageFromGroup', { name: data.body.group.name }), { icon: data.body.user.avatarUrl, - tag: `messaging:group:${data.body.group.id}` + tag: `messaging:group:${data.body.group.id}`, + data, }]; default: return null; diff --git a/src/client/sw/sw.ts b/src/client/sw/sw.ts index e50a82f1bc..2608da042c 100644 --- a/src/client/sw/sw.ts +++ b/src/client/sw/sw.ts @@ -58,9 +58,11 @@ self.addEventListener('push', ev => { const data: pushNotificationData = ev.data?.json(); + console.log('push', data) + switch (data.type) { - case 'notification': // case 'driveFileCreated': + case 'notification': case 'unreadMessagingMessage': return createNotification(data); case 'readAllNotifications': @@ -83,6 +85,7 @@ self.addEventListener('push', ev => { //#region Notification self.addEventListener('notificationclick', ev => { const { action, notification } = ev; + console.log('click', action, notification) const data: pushNotificationData = notification.data; const { origin } = location; @@ -110,6 +113,8 @@ self.addEventListener('notificationclick', ev => { self.addEventListener('notificationclose', ev => { const { notification } = ev; + console.log('close', notification) + if (notification.title !== 'notificationclose') { self.registration.showNotification('notificationclose', { body: `${notification?.data?.body?.id}` }); }