メッセージタイムラインを追加
This commit is contained in:
parent
2fad6e6d5f
commit
ab83e08bc7
11 changed files with 393 additions and 150 deletions
|
@ -169,6 +169,7 @@ common:
|
||||||
hashtag: "ハッシュタグ"
|
hashtag: "ハッシュタグ"
|
||||||
global: "グローバル"
|
global: "グローバル"
|
||||||
mentions: "あなた宛て"
|
mentions: "あなた宛て"
|
||||||
|
direct: "ダイレクト投稿"
|
||||||
notifications: "通知"
|
notifications: "通知"
|
||||||
list: "リスト"
|
list: "リスト"
|
||||||
swap-left: "左に移動"
|
swap-left: "左に移動"
|
||||||
|
@ -916,6 +917,7 @@ desktop/views/components/timeline.vue:
|
||||||
hybrid: "ソーシャル"
|
hybrid: "ソーシャル"
|
||||||
global: "グローバル"
|
global: "グローバル"
|
||||||
mentions: "あなた宛て"
|
mentions: "あなた宛て"
|
||||||
|
messages: "メッセージ"
|
||||||
list: "リスト"
|
list: "リスト"
|
||||||
hashtag: "ハッシュタグ"
|
hashtag: "ハッシュタグ"
|
||||||
add-tag-timeline: "ハッシュタグを追加"
|
add-tag-timeline: "ハッシュタグを追加"
|
||||||
|
@ -1322,6 +1324,7 @@ mobile/views/pages/home.vue:
|
||||||
hybrid: "ソーシャル"
|
hybrid: "ソーシャル"
|
||||||
global: "グローバル"
|
global: "グローバル"
|
||||||
mentions: "あなた宛て"
|
mentions: "あなた宛て"
|
||||||
|
messages: "メッセージ"
|
||||||
|
|
||||||
mobile/views/pages/tag.vue:
|
mobile/views/pages/tag.vue:
|
||||||
no-posts-found: "ハッシュタグ「{}」が付けられた投稿は見つかりませんでした。"
|
no-posts-found: "ハッシュタグ「{}」が付けられた投稿は見つかりませんでした。"
|
||||||
|
|
|
@ -38,7 +38,14 @@ export default Vue.extend({
|
||||||
streamManager: null,
|
streamManager: null,
|
||||||
connection: null,
|
connection: null,
|
||||||
connectionId: null,
|
connectionId: null,
|
||||||
date: null
|
date: null,
|
||||||
|
baseQuery: {
|
||||||
|
includeMyRenotes: this.$store.state.settings.showMyRenotes,
|
||||||
|
includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes,
|
||||||
|
includeLocalRenotes: this.$store.state.settings.showLocalRenotes
|
||||||
|
},
|
||||||
|
query: {},
|
||||||
|
endpoint: null
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -47,53 +54,102 @@ export default Vue.extend({
|
||||||
return this.$store.state.i.followingCount == 0;
|
return this.$store.state.i.followingCount == 0;
|
||||||
},
|
},
|
||||||
|
|
||||||
endpoint(): string {
|
|
||||||
switch (this.src) {
|
|
||||||
case 'home': return 'notes/timeline';
|
|
||||||
case 'local': return 'notes/local-timeline';
|
|
||||||
case 'hybrid': return 'notes/hybrid-timeline';
|
|
||||||
case 'global': return 'notes/global-timeline';
|
|
||||||
case 'mentions': return 'notes/mentions';
|
|
||||||
case 'tag': return 'notes/search_by_tag';
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
canFetchMore(): boolean {
|
canFetchMore(): boolean {
|
||||||
return !this.moreFetching && !this.fetching && this.existMore;
|
return !this.moreFetching && !this.fetching && this.existMore;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
|
const prepend = note => {
|
||||||
|
(this.$refs.timeline as any).prepend(note);
|
||||||
|
};
|
||||||
|
|
||||||
if (this.src == 'tag') {
|
if (this.src == 'tag') {
|
||||||
|
this.endpoint = 'notes/search_by_tag';
|
||||||
|
this.query = {
|
||||||
|
query: this.tagTl.query
|
||||||
|
};
|
||||||
this.connection = new HashtagStream((this as any).os, this.$store.state.i, this.tagTl.query);
|
this.connection = new HashtagStream((this as any).os, this.$store.state.i, this.tagTl.query);
|
||||||
this.connection.on('note', this.onNote);
|
this.connection.on('note', prepend);
|
||||||
|
this.$once('beforeDestroy', () => {
|
||||||
|
this.connection.off('note', prepend);
|
||||||
|
this.connection.close();
|
||||||
|
});
|
||||||
} else if (this.src == 'home') {
|
} else if (this.src == 'home') {
|
||||||
|
this.endpoint = 'notes/timeline';
|
||||||
|
const onChangeFollowing = () => {
|
||||||
|
this.fetch();
|
||||||
|
};
|
||||||
this.streamManager = (this as any).os.stream;
|
this.streamManager = (this as any).os.stream;
|
||||||
this.connection = this.streamManager.getConnection();
|
this.connection = this.streamManager.getConnection();
|
||||||
this.connectionId = this.streamManager.use();
|
this.connectionId = this.streamManager.use();
|
||||||
this.connection.on('note', this.onNote);
|
this.connection.on('note', prepend);
|
||||||
this.connection.on('follow', this.onChangeFollowing);
|
this.connection.on('follow', onChangeFollowing);
|
||||||
this.connection.on('unfollow', this.onChangeFollowing);
|
this.connection.on('unfollow', onChangeFollowing);
|
||||||
|
this.$once('beforeDestroy', () => {
|
||||||
|
this.connection.off('note', prepend);
|
||||||
|
this.connection.off('follow', onChangeFollowing);
|
||||||
|
this.connection.off('unfollow', onChangeFollowing);
|
||||||
|
this.streamManager.dispose(this.connectionId);
|
||||||
|
});
|
||||||
} else if (this.src == 'local') {
|
} else if (this.src == 'local') {
|
||||||
|
this.endpoint = 'notes/local-timeline';
|
||||||
this.streamManager = (this as any).os.streams.localTimelineStream;
|
this.streamManager = (this as any).os.streams.localTimelineStream;
|
||||||
this.connection = this.streamManager.getConnection();
|
this.connection = this.streamManager.getConnection();
|
||||||
this.connectionId = this.streamManager.use();
|
this.connectionId = this.streamManager.use();
|
||||||
this.connection.on('note', this.onNote);
|
this.connection.on('note', prepend);
|
||||||
|
this.$once('beforeDestroy', () => {
|
||||||
|
this.connection.off('note', prepend);
|
||||||
|
this.streamManager.dispose(this.connectionId);
|
||||||
|
});
|
||||||
} else if (this.src == 'hybrid') {
|
} else if (this.src == 'hybrid') {
|
||||||
|
this.endpoint = 'notes/hybrid-timeline';
|
||||||
this.streamManager = (this as any).os.streams.hybridTimelineStream;
|
this.streamManager = (this as any).os.streams.hybridTimelineStream;
|
||||||
this.connection = this.streamManager.getConnection();
|
this.connection = this.streamManager.getConnection();
|
||||||
this.connectionId = this.streamManager.use();
|
this.connectionId = this.streamManager.use();
|
||||||
this.connection.on('note', this.onNote);
|
this.connection.on('note', prepend);
|
||||||
|
this.$once('beforeDestroy', () => {
|
||||||
|
this.connection.off('note', prepend);
|
||||||
|
this.streamManager.dispose(this.connectionId);
|
||||||
|
});
|
||||||
} else if (this.src == 'global') {
|
} else if (this.src == 'global') {
|
||||||
|
this.endpoint = 'notes/global-timeline';
|
||||||
this.streamManager = (this as any).os.streams.globalTimelineStream;
|
this.streamManager = (this as any).os.streams.globalTimelineStream;
|
||||||
this.connection = this.streamManager.getConnection();
|
this.connection = this.streamManager.getConnection();
|
||||||
this.connectionId = this.streamManager.use();
|
this.connectionId = this.streamManager.use();
|
||||||
this.connection.on('note', this.onNote);
|
this.connection.on('note', prepend);
|
||||||
|
this.$once('beforeDestroy', () => {
|
||||||
|
this.connection.off('note', prepend);
|
||||||
|
this.streamManager.dispose(this.connectionId);
|
||||||
|
});
|
||||||
} else if (this.src == 'mentions') {
|
} else if (this.src == 'mentions') {
|
||||||
|
this.endpoint = 'notes/mentions';
|
||||||
this.streamManager = (this as any).os.stream;
|
this.streamManager = (this as any).os.stream;
|
||||||
this.connection = this.streamManager.getConnection();
|
this.connection = this.streamManager.getConnection();
|
||||||
this.connectionId = this.streamManager.use();
|
this.connectionId = this.streamManager.use();
|
||||||
this.connection.on('mention', this.onNote);
|
this.connection.on('mention', prepend);
|
||||||
|
this.$once('beforeDestroy', () => {
|
||||||
|
this.connection.off('mention', prepend);
|
||||||
|
this.streamManager.dispose(this.connectionId);
|
||||||
|
});
|
||||||
|
} else if (this.src == 'messages') {
|
||||||
|
this.endpoint = 'notes/mentions';
|
||||||
|
this.query = {
|
||||||
|
visibility: 'specified'
|
||||||
|
};
|
||||||
|
const onNote = note => {
|
||||||
|
if (note.visibility == 'specified') {
|
||||||
|
prepend(note);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.streamManager = (this as any).os.stream;
|
||||||
|
this.connection = this.streamManager.getConnection();
|
||||||
|
this.connectionId = this.streamManager.use();
|
||||||
|
this.connection.on('mention', onNote);
|
||||||
|
this.$once('beforeDestroy', () => {
|
||||||
|
this.connection.off('mention', onNote);
|
||||||
|
this.streamManager.dispose(this.connectionId);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener('keydown', this.onKeydown);
|
document.addEventListener('keydown', this.onKeydown);
|
||||||
|
@ -102,28 +158,7 @@ export default Vue.extend({
|
||||||
},
|
},
|
||||||
|
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
if (this.src == 'tag') {
|
this.$emit('beforeDestroy');
|
||||||
this.connection.off('note', this.onNote);
|
|
||||||
this.connection.close();
|
|
||||||
} else if (this.src == 'home') {
|
|
||||||
this.connection.off('note', this.onNote);
|
|
||||||
this.connection.off('follow', this.onChangeFollowing);
|
|
||||||
this.connection.off('unfollow', this.onChangeFollowing);
|
|
||||||
this.streamManager.dispose(this.connectionId);
|
|
||||||
} else if (this.src == 'local') {
|
|
||||||
this.connection.off('note', this.onNote);
|
|
||||||
this.streamManager.dispose(this.connectionId);
|
|
||||||
} else if (this.src == 'hybrid') {
|
|
||||||
this.connection.off('note', this.onNote);
|
|
||||||
this.streamManager.dispose(this.connectionId);
|
|
||||||
} else if (this.src == 'global') {
|
|
||||||
this.connection.off('note', this.onNote);
|
|
||||||
this.streamManager.dispose(this.connectionId);
|
|
||||||
} else if (this.src == 'mentions') {
|
|
||||||
this.connection.off('mention', this.onNote);
|
|
||||||
this.streamManager.dispose(this.connectionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
document.removeEventListener('keydown', this.onKeydown);
|
document.removeEventListener('keydown', this.onKeydown);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -132,14 +167,10 @@ export default Vue.extend({
|
||||||
this.fetching = true;
|
this.fetching = true;
|
||||||
|
|
||||||
(this.$refs.timeline as any).init(() => new Promise((res, rej) => {
|
(this.$refs.timeline as any).init(() => new Promise((res, rej) => {
|
||||||
(this as any).api(this.endpoint, {
|
(this as any).api(this.endpoint, Object.assign({
|
||||||
limit: fetchLimit + 1,
|
limit: fetchLimit + 1,
|
||||||
untilDate: this.date ? this.date.getTime() : undefined,
|
untilDate: this.date ? this.date.getTime() : undefined
|
||||||
includeMyRenotes: this.$store.state.settings.showMyRenotes,
|
}, this.baseQuery, this.query)).then(notes => {
|
||||||
includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes,
|
|
||||||
includeLocalRenotes: this.$store.state.settings.showLocalRenotes,
|
|
||||||
query: this.tagTl ? this.tagTl.query : undefined
|
|
||||||
}).then(notes => {
|
|
||||||
if (notes.length == fetchLimit + 1) {
|
if (notes.length == fetchLimit + 1) {
|
||||||
notes.pop();
|
notes.pop();
|
||||||
this.existMore = true;
|
this.existMore = true;
|
||||||
|
@ -156,14 +187,10 @@ export default Vue.extend({
|
||||||
|
|
||||||
this.moreFetching = true;
|
this.moreFetching = true;
|
||||||
|
|
||||||
const promise = (this as any).api(this.endpoint, {
|
const promise = (this as any).api(this.endpoint, Object.assign({
|
||||||
limit: fetchLimit + 1,
|
limit: fetchLimit + 1,
|
||||||
untilId: (this.$refs.timeline as any).tail().id,
|
untilId: (this.$refs.timeline as any).tail().id
|
||||||
includeMyRenotes: this.$store.state.settings.showMyRenotes,
|
}, this.baseQuery, this.query));
|
||||||
includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes,
|
|
||||||
includeLocalRenotes: this.$store.state.settings.showLocalRenotes,
|
|
||||||
query: this.tagTl ? this.tagTl.query : undefined
|
|
||||||
});
|
|
||||||
|
|
||||||
promise.then(notes => {
|
promise.then(notes => {
|
||||||
if (notes.length == fetchLimit + 1) {
|
if (notes.length == fetchLimit + 1) {
|
||||||
|
@ -178,15 +205,6 @@ export default Vue.extend({
|
||||||
return promise;
|
return promise;
|
||||||
},
|
},
|
||||||
|
|
||||||
onNote(note) {
|
|
||||||
// Prepend a note
|
|
||||||
(this.$refs.timeline as any).prepend(note);
|
|
||||||
},
|
|
||||||
|
|
||||||
onChangeFollowing() {
|
|
||||||
this.fetch();
|
|
||||||
},
|
|
||||||
|
|
||||||
focus() {
|
focus() {
|
||||||
(this.$refs.timeline as any).focus();
|
(this.$refs.timeline as any).focus();
|
||||||
},
|
},
|
||||||
|
|
|
@ -5,10 +5,11 @@
|
||||||
<span :data-active="src == 'local'" @click="src = 'local'" v-if="enableLocalTimeline">%fa:R comments% %i18n:@local%</span>
|
<span :data-active="src == 'local'" @click="src = 'local'" v-if="enableLocalTimeline">%fa:R comments% %i18n:@local%</span>
|
||||||
<span :data-active="src == 'hybrid'" @click="src = 'hybrid'" v-if="enableLocalTimeline">%fa:share-alt% %i18n:@hybrid%</span>
|
<span :data-active="src == 'hybrid'" @click="src = 'hybrid'" v-if="enableLocalTimeline">%fa:share-alt% %i18n:@hybrid%</span>
|
||||||
<span :data-active="src == 'global'" @click="src = 'global'">%fa:globe% %i18n:@global%</span>
|
<span :data-active="src == 'global'" @click="src = 'global'">%fa:globe% %i18n:@global%</span>
|
||||||
<span :data-active="src == 'mentions'" @click="src = 'mentions'">%fa:at% %i18n:@mentions%</span>
|
|
||||||
<span :data-active="src == 'tag'" @click="src = 'tag'" v-if="tagTl">%fa:hashtag% {{ tagTl.title }}</span>
|
<span :data-active="src == 'tag'" @click="src = 'tag'" v-if="tagTl">%fa:hashtag% {{ tagTl.title }}</span>
|
||||||
<span :data-active="src == 'list'" @click="src = 'list'" v-if="list">%fa:list% {{ list.title }}</span>
|
<span :data-active="src == 'list'" @click="src = 'list'" v-if="list">%fa:list% {{ list.title }}</span>
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
|
<button :data-active="src == 'mentions'" @click="src = 'mentions'" title="%i18n:@mentions%">%fa:at%</button>
|
||||||
|
<button :data-active="src == 'messages'" @click="src = 'messages'" title="%i18n:@messages%">%fa:envelope R%</button>
|
||||||
<button @click="chooseTag" title="%i18n:@hashtag%" ref="tagButton">%fa:hashtag%</button>
|
<button @click="chooseTag" title="%i18n:@hashtag%" ref="tagButton">%fa:hashtag%</button>
|
||||||
<button @click="chooseList" title="%i18n:@list%" ref="listButton">%fa:list%</button>
|
<button @click="chooseList" title="%i18n:@list%" ref="listButton">%fa:list%</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -18,6 +19,7 @@
|
||||||
<x-core v-if="src == 'hybrid'" ref="tl" key="hybrid" src="hybrid"/>
|
<x-core v-if="src == 'hybrid'" ref="tl" key="hybrid" src="hybrid"/>
|
||||||
<x-core v-if="src == 'global'" ref="tl" key="global" src="global"/>
|
<x-core v-if="src == 'global'" ref="tl" key="global" src="global"/>
|
||||||
<x-core v-if="src == 'mentions'" ref="tl" key="mentions" src="mentions"/>
|
<x-core v-if="src == 'mentions'" ref="tl" key="mentions" src="mentions"/>
|
||||||
|
<x-core v-if="src == 'messages'" ref="tl" key="messages" src="messages"/>
|
||||||
<x-core v-if="src == 'tag'" ref="tl" key="tag" src="tag" :tag-tl="tagTl"/>
|
<x-core v-if="src == 'tag'" ref="tl" key="tag" src="tag" :tag-tl="tagTl"/>
|
||||||
<mk-user-list-timeline v-if="src == 'list'" ref="tl" :key="list.id" :list="list"/>
|
<mk-user-list-timeline v-if="src == 'list'" ref="tl" :key="list.id" :list="list"/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -202,6 +204,20 @@ root(isDark)
|
||||||
&:active
|
&:active
|
||||||
color isDark ? #b2c1d5 : #999
|
color isDark ? #b2c1d5 : #999
|
||||||
|
|
||||||
|
&[data-active]
|
||||||
|
color $theme-color
|
||||||
|
cursor default
|
||||||
|
|
||||||
|
&:before
|
||||||
|
content ""
|
||||||
|
display block
|
||||||
|
position absolute
|
||||||
|
bottom 0
|
||||||
|
left 0
|
||||||
|
width 100%
|
||||||
|
height 2px
|
||||||
|
background $theme-color
|
||||||
|
|
||||||
> span
|
> span
|
||||||
display inline-block
|
display inline-block
|
||||||
padding 0 10px
|
padding 0 10px
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
<x-tl-column v-else-if="column.type == 'list'" :column="column" :is-stacked="isStacked"/>
|
<x-tl-column v-else-if="column.type == 'list'" :column="column" :is-stacked="isStacked"/>
|
||||||
<x-tl-column v-else-if="column.type == 'hashtag'" :column="column" :is-stacked="isStacked"/>
|
<x-tl-column v-else-if="column.type == 'hashtag'" :column="column" :is-stacked="isStacked"/>
|
||||||
<x-mentions-column v-else-if="column.type == 'mentions'" :column="column" :is-stacked="isStacked"/>
|
<x-mentions-column v-else-if="column.type == 'mentions'" :column="column" :is-stacked="isStacked"/>
|
||||||
|
<x-direct-column v-else-if="column.type == 'direct'" :column="column" :is-stacked="isStacked"/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
@ -16,13 +17,15 @@ import XTlColumn from './deck.tl-column.vue';
|
||||||
import XNotificationsColumn from './deck.notifications-column.vue';
|
import XNotificationsColumn from './deck.notifications-column.vue';
|
||||||
import XWidgetsColumn from './deck.widgets-column.vue';
|
import XWidgetsColumn from './deck.widgets-column.vue';
|
||||||
import XMentionsColumn from './deck.mentions-column.vue';
|
import XMentionsColumn from './deck.mentions-column.vue';
|
||||||
|
import XDirectColumn from './deck.direct-column.vue';
|
||||||
|
|
||||||
export default Vue.extend({
|
export default Vue.extend({
|
||||||
components: {
|
components: {
|
||||||
XTlColumn,
|
XTlColumn,
|
||||||
XNotificationsColumn,
|
XNotificationsColumn,
|
||||||
XWidgetsColumn,
|
XWidgetsColumn,
|
||||||
XMentionsColumn
|
XMentionsColumn,
|
||||||
|
XDirectColumn
|
||||||
},
|
},
|
||||||
|
|
||||||
props: {
|
props: {
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
<template>
|
||||||
|
<x-column :name="name" :column="column" :is-stacked="isStacked">
|
||||||
|
<span slot="header">%fa:envelope R%{{ name }}</span>
|
||||||
|
|
||||||
|
<x-direct/>
|
||||||
|
</x-column>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import Vue from 'vue';
|
||||||
|
import XColumn from './deck.column.vue';
|
||||||
|
import XDirect from './deck.direct.vue';
|
||||||
|
|
||||||
|
export default Vue.extend({
|
||||||
|
components: {
|
||||||
|
XColumn,
|
||||||
|
XDirect
|
||||||
|
},
|
||||||
|
|
||||||
|
props: {
|
||||||
|
column: {
|
||||||
|
type: Object,
|
||||||
|
required: true
|
||||||
|
},
|
||||||
|
isStacked: {
|
||||||
|
type: Boolean,
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
computed: {
|
||||||
|
name(): string {
|
||||||
|
if (this.column.name) return this.column.name;
|
||||||
|
return '%i18n:common.deck.direct%';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
</script>
|
97
src/client/app/desktop/views/pages/deck/deck.direct.vue
Normal file
97
src/client/app/desktop/views/pages/deck/deck.direct.vue
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
<template>
|
||||||
|
<x-notes ref="timeline" :more="existMore ? more : null"/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import Vue from 'vue';
|
||||||
|
import XNotes from './deck.notes.vue';
|
||||||
|
|
||||||
|
const fetchLimit = 10;
|
||||||
|
|
||||||
|
export default Vue.extend({
|
||||||
|
components: {
|
||||||
|
XNotes
|
||||||
|
},
|
||||||
|
|
||||||
|
props: {
|
||||||
|
},
|
||||||
|
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
fetching: true,
|
||||||
|
moreFetching: false,
|
||||||
|
existMore: false,
|
||||||
|
connection: null,
|
||||||
|
connectionId: null
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted() {
|
||||||
|
this.connection = (this as any).os.stream.getConnection();
|
||||||
|
this.connectionId = (this as any).os.stream.use();
|
||||||
|
|
||||||
|
this.connection.on('mention', this.onNote);
|
||||||
|
|
||||||
|
this.fetch();
|
||||||
|
},
|
||||||
|
|
||||||
|
beforeDestroy() {
|
||||||
|
this.connection.off('mention', this.onNote);
|
||||||
|
(this as any).os.stream.dispose(this.connectionId);
|
||||||
|
},
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
fetch() {
|
||||||
|
this.fetching = true;
|
||||||
|
|
||||||
|
(this.$refs.timeline as any).init(() => new Promise((res, rej) => {
|
||||||
|
(this as any).api('notes/mentions', {
|
||||||
|
limit: fetchLimit + 1,
|
||||||
|
includeMyRenotes: this.$store.state.settings.showMyRenotes,
|
||||||
|
includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes,
|
||||||
|
includeLocalRenotes: this.$store.state.settings.showLocalRenotes,
|
||||||
|
visibility: 'specified'
|
||||||
|
}).then(notes => {
|
||||||
|
if (notes.length == fetchLimit + 1) {
|
||||||
|
notes.pop();
|
||||||
|
this.existMore = true;
|
||||||
|
}
|
||||||
|
res(notes);
|
||||||
|
this.fetching = false;
|
||||||
|
this.$emit('loaded');
|
||||||
|
}, rej);
|
||||||
|
}));
|
||||||
|
},
|
||||||
|
more() {
|
||||||
|
this.moreFetching = true;
|
||||||
|
|
||||||
|
const promise = (this as any).api('notes/mentions', {
|
||||||
|
limit: fetchLimit + 1,
|
||||||
|
untilId: (this.$refs.timeline as any).tail().id,
|
||||||
|
includeMyRenotes: this.$store.state.settings.showMyRenotes,
|
||||||
|
includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes,
|
||||||
|
includeLocalRenotes: this.$store.state.settings.showLocalRenotes,
|
||||||
|
visibility: 'specified'
|
||||||
|
});
|
||||||
|
|
||||||
|
promise.then(notes => {
|
||||||
|
if (notes.length == fetchLimit + 1) {
|
||||||
|
notes.pop();
|
||||||
|
} else {
|
||||||
|
this.existMore = false;
|
||||||
|
}
|
||||||
|
notes.forEach(n => (this.$refs.timeline as any).append(n));
|
||||||
|
this.moreFetching = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
return promise;
|
||||||
|
},
|
||||||
|
onNote(note) {
|
||||||
|
// Prepend a note
|
||||||
|
if (note.visibility == 'specified') {
|
||||||
|
(this.$refs.timeline as any).prepend(note);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -147,6 +147,15 @@ export default Vue.extend({
|
||||||
type: 'mentions'
|
type: 'mentions'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}, {
|
||||||
|
icon: '%fa:envelope R%',
|
||||||
|
text: '%i18n:common.deck.direct%',
|
||||||
|
action: () => {
|
||||||
|
this.$store.dispatch('settings/addDeckColumn', {
|
||||||
|
id: uuid(),
|
||||||
|
type: 'direct'
|
||||||
|
});
|
||||||
|
}
|
||||||
}, {
|
}, {
|
||||||
icon: '%fa:list%',
|
icon: '%fa:list%',
|
||||||
text: '%i18n:common.deck.list%',
|
text: '%i18n:common.deck.list%',
|
||||||
|
|
|
@ -37,7 +37,14 @@ export default Vue.extend({
|
||||||
connection: null,
|
connection: null,
|
||||||
connectionId: null,
|
connectionId: null,
|
||||||
unreadCount: 0,
|
unreadCount: 0,
|
||||||
date: null
|
date: null,
|
||||||
|
baseQuery: {
|
||||||
|
includeMyRenotes: this.$store.state.settings.showMyRenotes,
|
||||||
|
includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes,
|
||||||
|
includeLocalRenotes: this.$store.state.settings.showLocalRenotes
|
||||||
|
},
|
||||||
|
query: {},
|
||||||
|
endpoint: null
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -46,80 +53,109 @@ export default Vue.extend({
|
||||||
return this.$store.state.i.followingCount == 0;
|
return this.$store.state.i.followingCount == 0;
|
||||||
},
|
},
|
||||||
|
|
||||||
endpoint(): string {
|
|
||||||
switch (this.src) {
|
|
||||||
case 'home': return 'notes/timeline';
|
|
||||||
case 'local': return 'notes/local-timeline';
|
|
||||||
case 'hybrid': return 'notes/hybrid-timeline';
|
|
||||||
case 'global': return 'notes/global-timeline';
|
|
||||||
case 'mentions': return 'notes/mentions';
|
|
||||||
case 'tag': return 'notes/search_by_tag';
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
canFetchMore(): boolean {
|
canFetchMore(): boolean {
|
||||||
return !this.moreFetching && !this.fetching && this.existMore;
|
return !this.moreFetching && !this.fetching && this.existMore;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
|
const prepend = note => {
|
||||||
|
(this.$refs.timeline as any).prepend(note);
|
||||||
|
};
|
||||||
|
|
||||||
if (this.src == 'tag') {
|
if (this.src == 'tag') {
|
||||||
|
this.endpoint = 'notes/search_by_tag';
|
||||||
|
this.query = {
|
||||||
|
query: this.tagTl.query
|
||||||
|
};
|
||||||
this.connection = new HashtagStream((this as any).os, this.$store.state.i, this.tagTl.query);
|
this.connection = new HashtagStream((this as any).os, this.$store.state.i, this.tagTl.query);
|
||||||
this.connection.on('note', this.onNote);
|
this.connection.on('note', prepend);
|
||||||
|
this.$once('beforeDestroy', () => {
|
||||||
|
this.connection.off('note', prepend);
|
||||||
|
this.connection.close();
|
||||||
|
});
|
||||||
} else if (this.src == 'home') {
|
} else if (this.src == 'home') {
|
||||||
|
this.endpoint = 'notes/timeline';
|
||||||
|
const onChangeFollowing = () => {
|
||||||
|
this.fetch();
|
||||||
|
};
|
||||||
this.streamManager = (this as any).os.stream;
|
this.streamManager = (this as any).os.stream;
|
||||||
this.connection = this.streamManager.getConnection();
|
this.connection = this.streamManager.getConnection();
|
||||||
this.connectionId = this.streamManager.use();
|
this.connectionId = this.streamManager.use();
|
||||||
this.connection.on('note', this.onNote);
|
this.connection.on('note', prepend);
|
||||||
this.connection.on('follow', this.onChangeFollowing);
|
this.connection.on('follow', onChangeFollowing);
|
||||||
this.connection.on('unfollow', this.onChangeFollowing);
|
this.connection.on('unfollow', onChangeFollowing);
|
||||||
|
this.$once('beforeDestroy', () => {
|
||||||
|
this.connection.off('note', prepend);
|
||||||
|
this.connection.off('follow', onChangeFollowing);
|
||||||
|
this.connection.off('unfollow', onChangeFollowing);
|
||||||
|
this.streamManager.dispose(this.connectionId);
|
||||||
|
});
|
||||||
} else if (this.src == 'local') {
|
} else if (this.src == 'local') {
|
||||||
|
this.endpoint = 'notes/local-timeline';
|
||||||
this.streamManager = (this as any).os.streams.localTimelineStream;
|
this.streamManager = (this as any).os.streams.localTimelineStream;
|
||||||
this.connection = this.streamManager.getConnection();
|
this.connection = this.streamManager.getConnection();
|
||||||
this.connectionId = this.streamManager.use();
|
this.connectionId = this.streamManager.use();
|
||||||
this.connection.on('note', this.onNote);
|
this.connection.on('note', prepend);
|
||||||
|
this.$once('beforeDestroy', () => {
|
||||||
|
this.connection.off('note', prepend);
|
||||||
|
this.streamManager.dispose(this.connectionId);
|
||||||
|
});
|
||||||
} else if (this.src == 'hybrid') {
|
} else if (this.src == 'hybrid') {
|
||||||
|
this.endpoint = 'notes/hybrid-timeline';
|
||||||
this.streamManager = (this as any).os.streams.hybridTimelineStream;
|
this.streamManager = (this as any).os.streams.hybridTimelineStream;
|
||||||
this.connection = this.streamManager.getConnection();
|
this.connection = this.streamManager.getConnection();
|
||||||
this.connectionId = this.streamManager.use();
|
this.connectionId = this.streamManager.use();
|
||||||
this.connection.on('note', this.onNote);
|
this.connection.on('note', prepend);
|
||||||
|
this.$once('beforeDestroy', () => {
|
||||||
|
this.connection.off('note', prepend);
|
||||||
|
this.streamManager.dispose(this.connectionId);
|
||||||
|
});
|
||||||
} else if (this.src == 'global') {
|
} else if (this.src == 'global') {
|
||||||
|
this.endpoint = 'notes/global-timeline';
|
||||||
this.streamManager = (this as any).os.streams.globalTimelineStream;
|
this.streamManager = (this as any).os.streams.globalTimelineStream;
|
||||||
this.connection = this.streamManager.getConnection();
|
this.connection = this.streamManager.getConnection();
|
||||||
this.connectionId = this.streamManager.use();
|
this.connectionId = this.streamManager.use();
|
||||||
this.connection.on('note', this.onNote);
|
this.connection.on('note', prepend);
|
||||||
|
this.$once('beforeDestroy', () => {
|
||||||
|
this.connection.off('note', prepend);
|
||||||
|
this.streamManager.dispose(this.connectionId);
|
||||||
|
});
|
||||||
} else if (this.src == 'mentions') {
|
} else if (this.src == 'mentions') {
|
||||||
|
this.endpoint = 'notes/mentions';
|
||||||
this.streamManager = (this as any).os.stream;
|
this.streamManager = (this as any).os.stream;
|
||||||
this.connection = this.streamManager.getConnection();
|
this.connection = this.streamManager.getConnection();
|
||||||
this.connectionId = this.streamManager.use();
|
this.connectionId = this.streamManager.use();
|
||||||
this.connection.on('mention', this.onNote);
|
this.connection.on('mention', prepend);
|
||||||
|
this.$once('beforeDestroy', () => {
|
||||||
|
this.connection.off('mention', prepend);
|
||||||
|
this.streamManager.dispose(this.connectionId);
|
||||||
|
});
|
||||||
|
} else if (this.src == 'messages') {
|
||||||
|
this.endpoint = 'notes/mentions';
|
||||||
|
this.query = {
|
||||||
|
visibility: 'specified'
|
||||||
|
};
|
||||||
|
const onNote = note => {
|
||||||
|
if (note.visibility == 'specified') {
|
||||||
|
prepend(note);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
this.streamManager = (this as any).os.stream;
|
||||||
|
this.connection = this.streamManager.getConnection();
|
||||||
|
this.connectionId = this.streamManager.use();
|
||||||
|
this.connection.on('mention', onNote);
|
||||||
|
this.$once('beforeDestroy', () => {
|
||||||
|
this.connection.off('mention', onNote);
|
||||||
|
this.streamManager.dispose(this.connectionId);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.fetch();
|
this.fetch();
|
||||||
},
|
},
|
||||||
|
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
if (this.src == 'tag') {
|
this.$emit('beforeDestroy');
|
||||||
this.connection.off('note', this.onNote);
|
|
||||||
this.connection.close();
|
|
||||||
} else if (this.src == 'home') {
|
|
||||||
this.connection.off('note', this.onNote);
|
|
||||||
this.connection.off('follow', this.onChangeFollowing);
|
|
||||||
this.connection.off('unfollow', this.onChangeFollowing);
|
|
||||||
this.streamManager.dispose(this.connectionId);
|
|
||||||
} else if (this.src == 'local') {
|
|
||||||
this.connection.off('note', this.onNote);
|
|
||||||
this.streamManager.dispose(this.connectionId);
|
|
||||||
} else if (this.src == 'hybrid') {
|
|
||||||
this.connection.off('note', this.onNote);
|
|
||||||
this.streamManager.dispose(this.connectionId);
|
|
||||||
} else if (this.src == 'global') {
|
|
||||||
this.connection.off('note', this.onNote);
|
|
||||||
this.streamManager.dispose(this.connectionId);
|
|
||||||
} else if (this.src == 'mentions') {
|
|
||||||
this.connection.off('mention', this.onNote);
|
|
||||||
this.streamManager.dispose(this.connectionId);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
@ -127,14 +163,10 @@ export default Vue.extend({
|
||||||
this.fetching = true;
|
this.fetching = true;
|
||||||
|
|
||||||
(this.$refs.timeline as any).init(() => new Promise((res, rej) => {
|
(this.$refs.timeline as any).init(() => new Promise((res, rej) => {
|
||||||
(this as any).api(this.endpoint, {
|
(this as any).api(this.endpoint, Object.assign({
|
||||||
limit: fetchLimit + 1,
|
limit: fetchLimit + 1,
|
||||||
untilDate: this.date ? this.date.getTime() : undefined,
|
untilDate: this.date ? this.date.getTime() : undefined
|
||||||
includeMyRenotes: this.$store.state.settings.showMyRenotes,
|
}, this.baseQuery, this.query)).then(notes => {
|
||||||
includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes,
|
|
||||||
includeLocalRenotes: this.$store.state.settings.showLocalRenotes,
|
|
||||||
query: this.tagTl ? this.tagTl.query : undefined
|
|
||||||
}).then(notes => {
|
|
||||||
if (notes.length == fetchLimit + 1) {
|
if (notes.length == fetchLimit + 1) {
|
||||||
notes.pop();
|
notes.pop();
|
||||||
this.existMore = true;
|
this.existMore = true;
|
||||||
|
@ -151,14 +183,10 @@ export default Vue.extend({
|
||||||
|
|
||||||
this.moreFetching = true;
|
this.moreFetching = true;
|
||||||
|
|
||||||
const promise = (this as any).api(this.endpoint, {
|
const promise = (this as any).api(this.endpoint, Object.assign({
|
||||||
limit: fetchLimit + 1,
|
limit: fetchLimit + 1,
|
||||||
untilId: (this.$refs.timeline as any).tail().id,
|
untilId: (this.$refs.timeline as any).tail().id
|
||||||
includeMyRenotes: this.$store.state.settings.showMyRenotes,
|
}, this.baseQuery, this.query));
|
||||||
includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes,
|
|
||||||
includeLocalRenotes: this.$store.state.settings.showLocalRenotes,
|
|
||||||
query: this.tagTl ? this.tagTl.query : undefined
|
|
||||||
});
|
|
||||||
|
|
||||||
promise.then(notes => {
|
promise.then(notes => {
|
||||||
if (notes.length == fetchLimit + 1) {
|
if (notes.length == fetchLimit + 1) {
|
||||||
|
@ -173,15 +201,6 @@ export default Vue.extend({
|
||||||
return promise;
|
return promise;
|
||||||
},
|
},
|
||||||
|
|
||||||
onNote(note) {
|
|
||||||
// Prepend a note
|
|
||||||
(this.$refs.timeline as any).prepend(note);
|
|
||||||
},
|
|
||||||
|
|
||||||
onChangeFollowing() {
|
|
||||||
this.fetch();
|
|
||||||
},
|
|
||||||
|
|
||||||
focus() {
|
focus() {
|
||||||
(this.$refs.timeline as any).focus();
|
(this.$refs.timeline as any).focus();
|
||||||
},
|
},
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
<span v-if="src == 'hybrid'">%fa:share-alt%%i18n:@hybrid%</span>
|
<span v-if="src == 'hybrid'">%fa:share-alt%%i18n:@hybrid%</span>
|
||||||
<span v-if="src == 'global'">%fa:globe%%i18n:@global%</span>
|
<span v-if="src == 'global'">%fa:globe%%i18n:@global%</span>
|
||||||
<span v-if="src == 'mentions'">%fa:at%%i18n:@mentions%</span>
|
<span v-if="src == 'mentions'">%fa:at%%i18n:@mentions%</span>
|
||||||
|
<span v-if="src == 'messages'">%fa:envelope R%%i18n:@messages%</span>
|
||||||
<span v-if="src == 'list'">%fa:list%{{ list.title }}</span>
|
<span v-if="src == 'list'">%fa:list%{{ list.title }}</span>
|
||||||
<span v-if="src == 'tag'">%fa:hashtag%{{ tagTl.title }}</span>
|
<span v-if="src == 'tag'">%fa:hashtag%{{ tagTl.title }}</span>
|
||||||
</span>
|
</span>
|
||||||
|
@ -23,16 +24,21 @@
|
||||||
<main :data-darkmode="$store.state.device.darkmode">
|
<main :data-darkmode="$store.state.device.darkmode">
|
||||||
<div class="nav" v-if="showNav">
|
<div class="nav" v-if="showNav">
|
||||||
<div class="bg" @click="showNav = false"></div>
|
<div class="bg" @click="showNav = false"></div>
|
||||||
|
<div class="pointer"></div>
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<div>
|
<div>
|
||||||
<span :data-active="src == 'home'" @click="src = 'home'">%fa:home% %i18n:@home%</span>
|
<span :data-active="src == 'home'" @click="src = 'home'">%fa:home% %i18n:@home%</span>
|
||||||
<span :data-active="src == 'local'" @click="src = 'local'" v-if="enableLocalTimeline">%fa:R comments% %i18n:@local%</span>
|
<span :data-active="src == 'local'" @click="src = 'local'" v-if="enableLocalTimeline">%fa:R comments% %i18n:@local%</span>
|
||||||
<span :data-active="src == 'hybrid'" @click="src = 'hybrid'" v-if="enableLocalTimeline">%fa:share-alt% %i18n:@hybrid%</span>
|
<span :data-active="src == 'hybrid'" @click="src = 'hybrid'" v-if="enableLocalTimeline">%fa:share-alt% %i18n:@hybrid%</span>
|
||||||
<span :data-active="src == 'global'" @click="src = 'global'">%fa:globe% %i18n:@global%</span>
|
<span :data-active="src == 'global'" @click="src = 'global'">%fa:globe% %i18n:@global%</span>
|
||||||
|
<div class="hr"></div>
|
||||||
<span :data-active="src == 'mentions'" @click="src = 'mentions'">%fa:at% %i18n:@mentions%</span>
|
<span :data-active="src == 'mentions'" @click="src = 'mentions'">%fa:at% %i18n:@mentions%</span>
|
||||||
|
<span :data-active="src == 'messages'" @click="src = 'messages'">%fa:envelope R% %i18n:@messages%</span>
|
||||||
<template v-if="lists">
|
<template v-if="lists">
|
||||||
|
<div class="hr"></div>
|
||||||
<span v-for="l in lists" :data-active="src == 'list' && list == l" @click="src = 'list'; list = l" :key="l.id">%fa:list% {{ l.title }}</span>
|
<span v-for="l in lists" :data-active="src == 'list' && list == l" @click="src = 'list'; list = l" :key="l.id">%fa:list% {{ l.title }}</span>
|
||||||
</template>
|
</template>
|
||||||
|
<div class="hr" v-if="$store.state.settings.tagTimelines && $store.state.settings.tagTimelines.length > 0"></div>
|
||||||
<span v-for="tl in $store.state.settings.tagTimelines" :data-active="src == 'tag' && tagTl == tl" @click="src = 'tag'; tagTl = tl" :key="tl.id">%fa:hashtag% {{ tl.title }}</span>
|
<span v-for="tl in $store.state.settings.tagTimelines" :data-active="src == 'tag' && tagTl == tl" @click="src = 'tag'; tagTl = tl" :key="tl.id">%fa:hashtag% {{ tl.title }}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -44,6 +50,7 @@
|
||||||
<x-tl v-if="src == 'hybrid'" ref="tl" key="hybrid" src="hybrid"/>
|
<x-tl v-if="src == 'hybrid'" ref="tl" key="hybrid" src="hybrid"/>
|
||||||
<x-tl v-if="src == 'global'" ref="tl" key="global" src="global"/>
|
<x-tl v-if="src == 'global'" ref="tl" key="global" src="global"/>
|
||||||
<x-tl v-if="src == 'mentions'" ref="tl" key="mentions" src="mentions"/>
|
<x-tl v-if="src == 'mentions'" ref="tl" key="mentions" src="mentions"/>
|
||||||
|
<x-tl v-if="src == 'messages'" ref="tl" key="messages" src="messages"/>
|
||||||
<x-tl v-if="src == 'tag'" ref="tl" key="tag" src="tag" :tag-tl="tagTl"/>
|
<x-tl v-if="src == 'tag'" ref="tl" key="tag" src="tag" :tag-tl="tagTl"/>
|
||||||
<mk-user-list-timeline v-if="src == 'list'" ref="tl" :key="list.id" :list="list"/>
|
<mk-user-list-timeline v-if="src == 'list'" ref="tl" :key="list.id" :list="list"/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -150,6 +157,26 @@ export default Vue.extend({
|
||||||
|
|
||||||
root(isDark)
|
root(isDark)
|
||||||
> .nav
|
> .nav
|
||||||
|
> .pointer
|
||||||
|
position fixed
|
||||||
|
z-index 10002
|
||||||
|
top 56px
|
||||||
|
left 0
|
||||||
|
right 0
|
||||||
|
|
||||||
|
$size = 16px
|
||||||
|
|
||||||
|
&:after
|
||||||
|
content ""
|
||||||
|
display block
|
||||||
|
position absolute
|
||||||
|
top -($size * 2)
|
||||||
|
left s('calc(50% - %s)', $size)
|
||||||
|
border-top solid $size transparent
|
||||||
|
border-left solid $size transparent
|
||||||
|
border-right solid $size transparent
|
||||||
|
border-bottom solid $size isDark ? #272f3a : #fff
|
||||||
|
|
||||||
> .bg
|
> .bg
|
||||||
position fixed
|
position fixed
|
||||||
z-index 10000
|
z-index 10000
|
||||||
|
@ -166,28 +193,22 @@ root(isDark)
|
||||||
left 0
|
left 0
|
||||||
right 0
|
right 0
|
||||||
width 300px
|
width 300px
|
||||||
|
max-height calc(100% - 70px)
|
||||||
margin 0 auto
|
margin 0 auto
|
||||||
|
overflow auto
|
||||||
|
-webkit-overflow-scrolling touch
|
||||||
background isDark ? #272f3a : #fff
|
background isDark ? #272f3a : #fff
|
||||||
border-radius 8px
|
border-radius 8px
|
||||||
box-shadow 0 0 16px rgba(#000, 0.1)
|
box-shadow 0 0 16px rgba(#000, 0.1)
|
||||||
|
|
||||||
$balloon-size = 16px
|
|
||||||
|
|
||||||
&:after
|
|
||||||
content ""
|
|
||||||
display block
|
|
||||||
position absolute
|
|
||||||
top -($balloon-size * 2) + 1.5px
|
|
||||||
left s('calc(50% - %s)', $balloon-size)
|
|
||||||
border-top solid $balloon-size transparent
|
|
||||||
border-left solid $balloon-size transparent
|
|
||||||
border-right solid $balloon-size transparent
|
|
||||||
border-bottom solid $balloon-size isDark ? #272f3a : #fff
|
|
||||||
|
|
||||||
> div
|
> div
|
||||||
padding 8px 0
|
padding 8px 0
|
||||||
|
|
||||||
> *
|
> .hr
|
||||||
|
margin 8px 0
|
||||||
|
border-top solid 1px isDark ? rgba(#000, 0.3) : rgba(#000, 0.1)
|
||||||
|
|
||||||
|
> *:not(.hr)
|
||||||
display block
|
display block
|
||||||
padding 8px 16px
|
padding 8px 16px
|
||||||
color isDark ? #cdd0d8 : #666
|
color isDark ? #cdd0d8 : #666
|
||||||
|
|
|
@ -27,6 +27,9 @@ export const meta = {
|
||||||
|
|
||||||
untilId: $.type(ID).optional.note({
|
untilId: $.type(ID).optional.note({
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
visibility: $.str.optional.note({
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -52,6 +55,10 @@ export default (params: any, user: ILocalUser) => new Promise(async (res, rej) =
|
||||||
_id: -1
|
_id: -1
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (ps.visibility) {
|
||||||
|
query.visibility = ps.visibility;
|
||||||
|
}
|
||||||
|
|
||||||
if (ps.following) {
|
if (ps.following) {
|
||||||
const followingIds = await getFriendIds(user._id);
|
const followingIds = await getFriendIds(user._id);
|
||||||
|
|
||||||
|
|
|
@ -142,6 +142,14 @@ export default async (user: IUser, data: Option, silent = false) => new Promise<
|
||||||
mentionedUsers.push(await User.findOne({ _id: data.reply.userId }));
|
mentionedUsers.push(await User.findOne({ _id: data.reply.userId }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data.visibility == 'specified') {
|
||||||
|
data.visibleUsers.forEach(u => {
|
||||||
|
if (!mentionedUsers.some(x => x._id.equals(u._id))) {
|
||||||
|
mentionedUsers.push(u);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const note = await insertNote(user, data, tags, mentionedUsers);
|
const note = await insertNote(user, data, tags, mentionedUsers);
|
||||||
|
|
||||||
res(note);
|
res(note);
|
||||||
|
@ -188,7 +196,7 @@ export default async (user: IUser, data: Option, silent = false) => new Promise<
|
||||||
const nm = new NotificationManager(user, note);
|
const nm = new NotificationManager(user, note);
|
||||||
const nmRelatedPromises = [];
|
const nmRelatedPromises = [];
|
||||||
|
|
||||||
createMentionedEvents(mentionedUsers, noteObj, nm);
|
createMentionedEvents(mentionedUsers, note, nm);
|
||||||
|
|
||||||
const noteActivity = await renderActivity(data, note);
|
const noteActivity = await renderActivity(data, note);
|
||||||
|
|
||||||
|
@ -318,7 +326,7 @@ async function publish(user: IUser, note: INote, noteObj: any, reply: INote, ren
|
||||||
|
|
||||||
if (['public', 'home', 'followers'].includes(note.visibility)) {
|
if (['public', 'home', 'followers'].includes(note.visibility)) {
|
||||||
// フォロワーに配信
|
// フォロワーに配信
|
||||||
publishToFollowers(note, noteObj, user, noteActivity);
|
publishToFollowers(note, user, noteActivity);
|
||||||
}
|
}
|
||||||
|
|
||||||
// リストに配信
|
// リストに配信
|
||||||
|
@ -456,7 +464,7 @@ async function publishToUserLists(note: INote, noteObj: any) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function publishToFollowers(note: INote, noteObj: any, user: IUser, noteActivity: any) {
|
async function publishToFollowers(note: INote, user: IUser, noteActivity: any) {
|
||||||
const detailPackedNote = await pack(note, null, {
|
const detailPackedNote = await pack(note, null, {
|
||||||
detail: true,
|
detail: true,
|
||||||
skipHide: true
|
skipHide: true
|
||||||
|
@ -505,9 +513,13 @@ function deliverNoteToMentionedRemoteUsers(mentionedUsers: IUser[], user: ILocal
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function createMentionedEvents(mentionedUsers: IUser[], noteObj: any, nm: NotificationManager) {
|
function createMentionedEvents(mentionedUsers: IUser[], note: INote, nm: NotificationManager) {
|
||||||
mentionedUsers.filter(u => isLocalUser(u)).forEach(async (u) => {
|
mentionedUsers.filter(u => isLocalUser(u)).forEach(async (u) => {
|
||||||
publishUserStream(u._id, 'mention', noteObj);
|
const detailPackedNote = await pack(note, u, {
|
||||||
|
detail: true
|
||||||
|
});
|
||||||
|
|
||||||
|
publishUserStream(u._id, 'mention', detailPackedNote);
|
||||||
|
|
||||||
// Create notification
|
// Create notification
|
||||||
nm.push(u._id, 'mention');
|
nm.push(u._id, 'mention');
|
||||||
|
|
Loading…
Reference in a new issue