diff options
| -rw-r--r-- | locales/en.yml | 3 | ||||
| -rw-r--r-- | locales/ja.yml | 3 | ||||
| -rw-r--r-- | src/api/common/read-messaging-message.ts | 2 | ||||
| -rw-r--r-- | src/api/endpoints/messaging/messages/create.ts | 3 | ||||
| -rw-r--r-- | src/api/event.ts | 6 | ||||
| -rw-r--r-- | src/api/stream/messaging-index.ts | 10 | ||||
| -rw-r--r-- | src/api/streaming.ts | 2 | ||||
| -rw-r--r-- | src/web/app/common/mixins/index.ts | 2 | ||||
| -rw-r--r-- | src/web/app/common/scripts/messaging-index-stream-manager.ts | 20 | ||||
| -rw-r--r-- | src/web/app/common/scripts/messaging-index-stream.ts | 14 | ||||
| -rw-r--r-- | src/web/app/common/tags/messaging/index.tag | 76 | ||||
| -rw-r--r-- | src/web/app/desktop/tags/home-widgets/messaging.tag | 50 | ||||
| -rw-r--r-- | src/web/app/desktop/tags/home.tag | 1 | ||||
| -rw-r--r-- | src/web/app/desktop/tags/index.ts | 1 |
14 files changed, 186 insertions, 7 deletions
diff --git a/locales/en.yml b/locales/en.yml index d464b2fe2f..d6fcd1e6d4 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -393,6 +393,9 @@ desktop: mk-access-log-home-widget: title: "Access log" + mk-messaging-home-widget: + title: "Messaging" + mk-repost-form: quote: "Quote..." cancel: "Cancel" diff --git a/locales/ja.yml b/locales/ja.yml index 5c6f8e38e1..478afac132 100644 --- a/locales/ja.yml +++ b/locales/ja.yml @@ -393,6 +393,9 @@ desktop: mk-access-log-home-widget: title: "アクセスログ" + mk-messaging-home-widget: + title: "メッセージ" + mk-repost-form: quote: "引用する..." cancel: "キャンセル" diff --git a/src/api/common/read-messaging-message.ts b/src/api/common/read-messaging-message.ts index 3257ec8b07..8e5e5b2b68 100644 --- a/src/api/common/read-messaging-message.ts +++ b/src/api/common/read-messaging-message.ts @@ -3,6 +3,7 @@ import Message from '../models/messaging-message'; import { IMessagingMessage as IMessage } from '../models/messaging-message'; import publishUserStream from '../event'; import { publishMessagingStream } from '../event'; +import { publishMessagingIndexStream } from '../event'; /** * Mark as read message(s) @@ -49,6 +50,7 @@ export default ( // Publish event publishMessagingStream(otherpartyId, userId, 'read', ids.map(id => id.toString())); + publishMessagingIndexStream(userId, 'read', ids.map(id => id.toString())); // Calc count of my unread messages const count = await Message diff --git a/src/api/endpoints/messaging/messages/create.ts b/src/api/endpoints/messaging/messages/create.ts index 149852c093..29a4671f84 100644 --- a/src/api/endpoints/messaging/messages/create.ts +++ b/src/api/endpoints/messaging/messages/create.ts @@ -10,6 +10,7 @@ import DriveFile from '../../../models/drive-file'; import serialize from '../../../serializers/messaging-message'; import publishUserStream from '../../../event'; import { publishMessagingStream } from '../../../event'; +import { publishMessagingIndexStream } from '../../../event'; import config from '../../../../conf'; /** @@ -85,10 +86,12 @@ module.exports = (params, user) => new Promise(async (res, rej) => { // 自分のストリーム publishMessagingStream(message.user_id, message.recipient_id, 'message', messageObj); + publishMessagingIndexStream(message.user_id, 'message', messageObj); publishUserStream(message.user_id, 'messaging_message', messageObj); // 相手のストリーム publishMessagingStream(message.recipient_id, message.user_id, 'message', messageObj); + publishMessagingIndexStream(message.recipient_id, 'message', messageObj); publishUserStream(message.recipient_id, 'messaging_message', messageObj); // 3秒経っても(今回作成した)メッセージが既読にならなかったら「未読のメッセージがありますよ」イベントを発行する diff --git a/src/api/event.ts b/src/api/event.ts index 909b0d2556..927883737e 100644 --- a/src/api/event.ts +++ b/src/api/event.ts @@ -25,6 +25,10 @@ class MisskeyEvent { this.publish(`messaging-stream:${userId}-${otherpartyId}`, type, typeof value === 'undefined' ? null : value); } + public publishMessagingIndexStream(userId: ID, type: string, value?: any): void { + this.publish(`messaging-index-stream:${userId}`, type, typeof value === 'undefined' ? null : value); + } + public publishChannelStream(channelId: ID, type: string, value?: any): void { this.publish(`channel-stream:${channelId}`, type, typeof value === 'undefined' ? null : value); } @@ -46,4 +50,6 @@ export const publishPostStream = ev.publishPostStream.bind(ev); export const publishMessagingStream = ev.publishMessagingStream.bind(ev); +export const publishMessagingIndexStream = ev.publishMessagingIndexStream.bind(ev); + export const publishChannelStream = ev.publishChannelStream.bind(ev); diff --git a/src/api/stream/messaging-index.ts b/src/api/stream/messaging-index.ts new file mode 100644 index 0000000000..c1b2fbc806 --- /dev/null +++ b/src/api/stream/messaging-index.ts @@ -0,0 +1,10 @@ +import * as websocket from 'websocket'; +import * as redis from 'redis'; + +export default function(request: websocket.request, connection: websocket.connection, subscriber: redis.RedisClient, user: any): void { + // Subscribe messaging index stream + subscriber.subscribe(`misskey:messaging-index-stream:${user._id}`); + subscriber.on('message', (_, data) => { + connection.send(data); + }); +} diff --git a/src/api/streaming.ts b/src/api/streaming.ts index 6caf7db3e8..1f0ba848c1 100644 --- a/src/api/streaming.ts +++ b/src/api/streaming.ts @@ -8,6 +8,7 @@ import isNativeToken from './common/is-native-token'; import homeStream from './stream/home'; import messagingStream from './stream/messaging'; +import messagingIndexStream from './stream/messaging-index'; import serverStream from './stream/server'; import requestsStream from './stream/requests'; import channelStream from './stream/channel'; @@ -58,6 +59,7 @@ module.exports = (server: http.Server) => { const channel = request.resourceURL.pathname === '/' ? homeStream : request.resourceURL.pathname === '/messaging' ? messagingStream : + request.resourceURL.pathname === '/messaging-index' ? messagingIndexStream : null; if (channel !== null) { diff --git a/src/web/app/common/mixins/index.ts b/src/web/app/common/mixins/index.ts index a11bfa7b64..c0c1c0555f 100644 --- a/src/web/app/common/mixins/index.ts +++ b/src/web/app/common/mixins/index.ts @@ -4,6 +4,7 @@ import activateMe from './i'; import activateApi from './api'; import ServerStreamManager from '../scripts/server-stream-manager'; import RequestsStreamManager from '../scripts/requests-stream-manager'; +import MessagingIndexStream from '../scripts/messaging-index-stream-manager'; export default (me, stream) => { activateMe(me); @@ -13,4 +14,5 @@ export default (me, stream) => { (riot as any).mixin('server-stream', { serverStream: new ServerStreamManager() }); (riot as any).mixin('requests-stream', { requestsStream: new RequestsStreamManager() }); + (riot as any).mixin('messaging-index-stream', { messagingIndexStream: new MessagingIndexStream(me) }); }; diff --git a/src/web/app/common/scripts/messaging-index-stream-manager.ts b/src/web/app/common/scripts/messaging-index-stream-manager.ts new file mode 100644 index 0000000000..dc386204ca --- /dev/null +++ b/src/web/app/common/scripts/messaging-index-stream-manager.ts @@ -0,0 +1,20 @@ +import StreamManager from './stream-manager'; +import Connection from './messaging-index-stream'; + +export default class ServerStreamManager extends StreamManager<Connection> { + private me; + + constructor(me) { + super(); + + this.me = me; + } + + public getConnection() { + if (this.connection == null) { + this.connection = new Connection(this.me); + } + + return this.connection; + } +} diff --git a/src/web/app/common/scripts/messaging-index-stream.ts b/src/web/app/common/scripts/messaging-index-stream.ts new file mode 100644 index 0000000000..c194e663c2 --- /dev/null +++ b/src/web/app/common/scripts/messaging-index-stream.ts @@ -0,0 +1,14 @@ +import Stream from './stream'; + +/** + * Messaging index stream connection + */ +class Connection extends Stream { + constructor(me) { + super('messaging-index', { + i: me.token + }); + } +} + +export default Connection; diff --git a/src/web/app/common/tags/messaging/index.tag b/src/web/app/common/tags/messaging/index.tag index 731c9da2c7..4c1bf0c6e4 100644 --- a/src/web/app/common/tags/messaging/index.tag +++ b/src/web/app/common/tags/messaging/index.tag @@ -1,5 +1,5 @@ -<mk-messaging> - <div class="search"> +<mk-messaging data-compact={ opts.compact }> + <div class="search" if={ !opts.compact }> <div class="form"> <label for="search-input"><i class="fa fa-search"></i></label> <input ref="search" type="search" oninput={ search } onkeydown={ onSearchKeydown } placeholder="%i18n:common.tags.mk-messaging.search-user%"/> @@ -36,6 +36,31 @@ :scope display block + &[data-compact] + font-size 0.8em + + > .history + > a + &:last-child + border-bottom none + + &:not([data-is-me]):not([data-is-read]) + > div + background-image none + border-left solid 4px #3aa2dc + + > div + padding 16px + + > header + > mk-time + font-size 1em + + > .avatar + width 42px + height 42px + margin 0 12px 0 0 + > .search display block position -webkit-sticky @@ -75,7 +100,7 @@ > input margin 0 - padding 0 12px 0 38px + padding 0 0 0 38px width 100% font-size 1em line-height 38px @@ -299,22 +324,59 @@ this.mixin('i'); this.mixin('api'); + this.mixin('messaging-index-stream'); + this.connection = this.messagingIndexStream.getConnection(); + this.connectionId = this.messagingIndexStream.use(); + this.searchResult = []; + this.registerMessage = message => { + message.is_me = message.user_id == this.I.id; + message._click = () => { + this.trigger('navigate-user', message.is_me ? message.recipient : message.user); + }; + }; + this.on('mount', () => { + this.connection.on('message', this.onMessage); + this.connection.on('read', this.onRead); + this.api('messaging/history').then(history => { this.isLoading = false; history.forEach(message => { - message.is_me = message.user_id == this.I.id - message._click = () => { - this.trigger('navigate-user', message.is_me ? message.recipient : message.user); - }; + this.registerMessage(message); }); this.history = history; this.update(); }); }); + this.on('unmount', () => { + this.connection.off('message', this.onMessage); + this.connection.off('read', this.onRead); + this.messagingIndexStream.dispose(this.connectionId); + }); + + this.onMessage = message => { + this.history = this.history.filter(m => !( + (m.recipient_id == message.recipient_id && m.user_id == message.user_id) || + (m.recipient_id == message.user_id && m.user_id == message.recipient_id))); + + this.registerMessage(message); + + this.history.unshift(message); + this.update(); + }; + + this.onRead = ids => { + ids.forEach(id => { + const found = this.history.find(m => m.id == id); + if (found) found.is_read = true; + }); + + this.update(); + }; + this.search = () => { const q = this.refs.search.value; if (q == '') { diff --git a/src/web/app/desktop/tags/home-widgets/messaging.tag b/src/web/app/desktop/tags/home-widgets/messaging.tag new file mode 100644 index 0000000000..d7e8375c8d --- /dev/null +++ b/src/web/app/desktop/tags/home-widgets/messaging.tag @@ -0,0 +1,50 @@ +<mk-messaging-home-widget> + <virtual if={ data.design == 0 }> + <p class="title"><i class="fa fa-comments"></i>%i18n:desktop.tags.mk-messaging-home-widget.title%</p> + </virtual> + <mk-messaging ref="index" compact={ true }/> + <style> + :scope + display block + overflow hidden + background #fff + + > .title + z-index 2 + margin 0 + padding 0 16px + line-height 42px + font-size 0.9em + font-weight bold + color #888 + box-shadow 0 1px rgba(0, 0, 0, 0.07) + + > i + margin-right 4px + + > mk-messaging + max-height 250px + overflow auto + + </style> + <script> + this.data = { + design: 0 + }; + + this.mixin('widget'); + + this.on('mount', () => { + this.refs.index.on('navigate-user', user => { + riot.mount(document.body.appendChild(document.createElement('mk-messaging-room-window')), { + user: user + }); + }); + }); + + this.func = () => { + if (++this.data.design == 2) this.data.design = 0; + this.save(); + }; + </script> +</mk-messaging-home-widget> diff --git a/src/web/app/desktop/tags/home.tag b/src/web/app/desktop/tags/home.tag index 88d06d2baa..5a0d194ba5 100644 --- a/src/web/app/desktop/tags/home.tag +++ b/src/web/app/desktop/tags/home.tag @@ -19,6 +19,7 @@ <option value="user-recommendation">おすすめユーザー</option> <option value="recommended-polls">投票</option> <option value="post-form">投稿フォーム</option> + <option value="messaging">メッセージ</option> <option value="channel">チャンネル</option> <option value="access-log">アクセスログ</option> <option value="server">サーバー情報</option> diff --git a/src/web/app/desktop/tags/index.ts b/src/web/app/desktop/tags/index.ts index 8b5a52d670..cd22dde352 100644 --- a/src/web/app/desktop/tags/index.ts +++ b/src/web/app/desktop/tags/index.ts @@ -44,6 +44,7 @@ require('./home-widgets/channel.tag'); require('./home-widgets/timemachine.tag'); require('./home-widgets/post-form.tag'); require('./home-widgets/access-log.tag'); +require('./home-widgets/messaging.tag'); require('./timeline.tag'); require('./messaging/window.tag'); require('./messaging/room-window.tag'); |