summaryrefslogtreecommitdiff
path: root/src/client
diff options
context:
space:
mode:
authorsyuilo <syuilotan@yahoo.co.jp>2018-04-17 14:52:28 +0900
committersyuilo <syuilotan@yahoo.co.jp>2018-04-17 14:52:28 +0900
commita0e640b1189a55c28aafe7d586d531731ad450a4 (patch)
treec8d0ed34511646f1b5a1e68ff24d7510b1c64e7b /src/client
parentキューのメモリ使用量を削減 (diff)
downloadmisskey-a0e640b1189a55c28aafe7d586d531731ad450a4.tar.gz
misskey-a0e640b1189a55c28aafe7d586d531731ad450a4.tar.bz2
misskey-a0e640b1189a55c28aafe7d586d531731ad450a4.zip
ローカルタイムラインとグローバルタイムラインを実装
Diffstat (limited to 'src/client')
-rw-r--r--src/client/app/common/mios.ts12
-rw-r--r--src/client/app/common/scripts/streaming/global-timeline.ts34
-rw-r--r--src/client/app/common/scripts/streaming/local-timeline.ts34
-rw-r--r--src/client/app/common/scripts/streaming/requests.ts30
-rw-r--r--src/client/app/desktop/views/components/timeline.core.vue175
-rw-r--r--src/client/app/desktop/views/components/timeline.vue148
6 files changed, 287 insertions, 146 deletions
diff --git a/src/client/app/common/mios.ts b/src/client/app/common/mios.ts
index 96a04bad3c..6d6d6b3e68 100644
--- a/src/client/app/common/mios.ts
+++ b/src/client/app/common/mios.ts
@@ -9,11 +9,12 @@ import Connection from './scripts/streaming/stream';
import { HomeStreamManager } from './scripts/streaming/home';
import { DriveStreamManager } from './scripts/streaming/drive';
import { ServerStreamManager } from './scripts/streaming/server';
-import { RequestsStreamManager } from './scripts/streaming/requests';
import { MessagingIndexStreamManager } from './scripts/streaming/messaging-index';
import { OthelloStreamManager } from './scripts/streaming/othello';
import Err from '../common/views/components/connect-failed.vue';
+import { LocalTimelineStreamManager } from './scripts/streaming/local-timeline';
+import { GlobalTimelineStreamManager } from './scripts/streaming/global-timeline';
//#region api requests
let spinner = null;
@@ -116,15 +117,17 @@ export default class MiOS extends EventEmitter {
* Connection managers
*/
public streams: {
+ localTimelineStream: LocalTimelineStreamManager;
+ globalTimelineStream: GlobalTimelineStreamManager;
driveStream: DriveStreamManager;
serverStream: ServerStreamManager;
- requestsStream: RequestsStreamManager;
messagingIndexStream: MessagingIndexStreamManager;
othelloStream: OthelloStreamManager;
} = {
+ localTimelineStream: null,
+ globalTimelineStream: null,
driveStream: null,
serverStream: null,
- requestsStream: null,
messagingIndexStream: null,
othelloStream: null
};
@@ -231,13 +234,14 @@ export default class MiOS extends EventEmitter {
public async init(callback) {
//#region Init stream managers
this.streams.serverStream = new ServerStreamManager(this);
- this.streams.requestsStream = new RequestsStreamManager(this);
this.once('signedin', () => {
// Init home stream manager
this.stream = new HomeStreamManager(this, this.i);
// Init other stream manager
+ this.streams.localTimelineStream = new LocalTimelineStreamManager(this, this.i);
+ this.streams.globalTimelineStream = new GlobalTimelineStreamManager(this, this.i);
this.streams.driveStream = new DriveStreamManager(this, this.i);
this.streams.messagingIndexStream = new MessagingIndexStreamManager(this, this.i);
this.streams.othelloStream = new OthelloStreamManager(this, this.i);
diff --git a/src/client/app/common/scripts/streaming/global-timeline.ts b/src/client/app/common/scripts/streaming/global-timeline.ts
new file mode 100644
index 0000000000..452ddbac03
--- /dev/null
+++ b/src/client/app/common/scripts/streaming/global-timeline.ts
@@ -0,0 +1,34 @@
+import Stream from './stream';
+import StreamManager from './stream-manager';
+import MiOS from '../../mios';
+
+/**
+ * Global timeline stream connection
+ */
+export class GlobalTimelineStream extends Stream {
+ constructor(os: MiOS, me) {
+ super(os, 'global-timeline', {
+ i: me.token
+ });
+ }
+}
+
+export class GlobalTimelineStreamManager extends StreamManager<GlobalTimelineStream> {
+ private me;
+ private os: MiOS;
+
+ constructor(os: MiOS, me) {
+ super();
+
+ this.me = me;
+ this.os = os;
+ }
+
+ public getConnection() {
+ if (this.connection == null) {
+ this.connection = new GlobalTimelineStream(this.os, this.me);
+ }
+
+ return this.connection;
+ }
+}
diff --git a/src/client/app/common/scripts/streaming/local-timeline.ts b/src/client/app/common/scripts/streaming/local-timeline.ts
new file mode 100644
index 0000000000..3d04e05cd4
--- /dev/null
+++ b/src/client/app/common/scripts/streaming/local-timeline.ts
@@ -0,0 +1,34 @@
+import Stream from './stream';
+import StreamManager from './stream-manager';
+import MiOS from '../../mios';
+
+/**
+ * Local timeline stream connection
+ */
+export class LocalTimelineStream extends Stream {
+ constructor(os: MiOS, me) {
+ super(os, 'local-timeline', {
+ i: me.token
+ });
+ }
+}
+
+export class LocalTimelineStreamManager extends StreamManager<LocalTimelineStream> {
+ private me;
+ private os: MiOS;
+
+ constructor(os: MiOS, me) {
+ super();
+
+ this.me = me;
+ this.os = os;
+ }
+
+ public getConnection() {
+ if (this.connection == null) {
+ this.connection = new LocalTimelineStream(this.os, this.me);
+ }
+
+ return this.connection;
+ }
+}
diff --git a/src/client/app/common/scripts/streaming/requests.ts b/src/client/app/common/scripts/streaming/requests.ts
deleted file mode 100644
index 5bec30143f..0000000000
--- a/src/client/app/common/scripts/streaming/requests.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-import Stream from './stream';
-import StreamManager from './stream-manager';
-import MiOS from '../../mios';
-
-/**
- * Requests stream connection
- */
-export class RequestsStream extends Stream {
- constructor(os: MiOS) {
- super(os, 'requests');
- }
-}
-
-export class RequestsStreamManager extends StreamManager<RequestsStream> {
- private os: MiOS;
-
- constructor(os: MiOS) {
- super();
-
- this.os = os;
- }
-
- public getConnection() {
- if (this.connection == null) {
- this.connection = new RequestsStream(this.os);
- }
-
- return this.connection;
- }
-}
diff --git a/src/client/app/desktop/views/components/timeline.core.vue b/src/client/app/desktop/views/components/timeline.core.vue
new file mode 100644
index 0000000000..8056e5b2c4
--- /dev/null
+++ b/src/client/app/desktop/views/components/timeline.core.vue
@@ -0,0 +1,175 @@
+<template>
+<div class="mk-home-timeline">
+ <mk-friends-maker v-if="src == 'home' && alone"/>
+ <div class="fetching" v-if="fetching">
+ <mk-ellipsis-icon/>
+ </div>
+ <p class="empty" v-if="notes.length == 0 && !fetching">
+ %fa:R comments%%i18n:@empty%
+ </p>
+ <mk-notes :notes="notes" ref="timeline">
+ <button slot="footer" @click="more" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }">
+ <template v-if="!moreFetching">%i18n:@load-more%</template>
+ <template v-if="moreFetching">%fa:spinner .pulse .fw%</template>
+ </button>
+ </mk-notes>
+</div>
+</template>
+
+<script lang="ts">
+import Vue from 'vue';
+import { url } from '../../../config';
+
+export default Vue.extend({
+ props: {
+ src: {
+ type: String,
+ required: true
+ }
+ },
+
+ data() {
+ return {
+ fetching: true,
+ moreFetching: false,
+ existMore: false,
+ notes: [],
+ connection: null,
+ connectionId: null,
+ date: null
+ };
+ },
+
+ computed: {
+ alone(): boolean {
+ return (this as any).os.i.followingCount == 0;
+ },
+
+ stream(): any {
+ return this.src == 'home'
+ ? (this as any).os.stream
+ : this.src == 'local'
+ ? (this as any).os.streams.localTimelineStream
+ : (this as any).os.streams.globalTimelineStream;
+ },
+
+ endpoint(): string {
+ return this.src == 'home'
+ ? 'notes/timeline'
+ : this.src == 'local'
+ ? 'notes/local-timeline'
+ : 'notes/global-timeline';
+ }
+ },
+
+ mounted() {
+ this.connection = this.stream.getConnection();
+ this.connectionId = this.stream.use();
+
+ this.connection.on('note', this.onNote);
+ if (this.src == 'home') {
+ this.connection.on('follow', this.onChangeFollowing);
+ this.connection.on('unfollow', this.onChangeFollowing);
+ }
+
+ this.fetch();
+ },
+
+ beforeDestroy() {
+ this.connection.off('note', this.onNote);
+ if (this.src == 'home') {
+ this.connection.off('follow', this.onChangeFollowing);
+ this.connection.off('unfollow', this.onChangeFollowing);
+ }
+ this.stream.dispose(this.connectionId);
+ },
+
+ methods: {
+ fetch(cb?) {
+ this.fetching = true;
+
+ (this as any).api('notes/timeline', {
+ limit: 11,
+ untilDate: this.date ? this.date.getTime() : undefined
+ }).then(notes => {
+ if (notes.length == 11) {
+ notes.pop();
+ this.existMore = true;
+ }
+ this.notes = notes;
+ this.fetching = false;
+ this.$emit('loaded');
+ if (cb) cb();
+ });
+ },
+
+ more() {
+ if (this.moreFetching || this.fetching || this.notes.length == 0 || !this.existMore) return;
+ this.moreFetching = true;
+ (this as any).api('notes/timeline', {
+ limit: 11,
+ untilId: this.notes[this.notes.length - 1].id
+ }).then(notes => {
+ if (notes.length == 11) {
+ notes.pop();
+ } else {
+ this.existMore = false;
+ }
+ this.notes = this.notes.concat(notes);
+ this.moreFetching = false;
+ });
+ },
+
+ onNote(note) {
+ // サウンドを再生する
+ if ((this as any).os.isEnableSounds) {
+ const sound = new Audio(`${url}/assets/post.mp3`);
+ sound.volume = localStorage.getItem('soundVolume') ? parseInt(localStorage.getItem('soundVolume'), 10) / 100 : 0.5;
+ sound.play();
+ }
+
+ this.notes.unshift(note);
+
+ const isTop = window.scrollY > 8;
+ if (isTop) this.notes.pop();
+ },
+
+ onChangeFollowing() {
+ this.fetch();
+ },
+
+ focus() {
+ (this.$refs.timeline as any).focus();
+ },
+
+ warp(date) {
+ this.date = date;
+ this.fetch();
+ }
+ }
+});
+</script>
+
+<style lang="stylus" scoped>
+.mk-home-timeline
+ > .mk-friends-maker
+ border-bottom solid 1px #eee
+
+ > .fetching
+ padding 64px 0
+
+ > .empty
+ display block
+ margin 0 auto
+ padding 32px
+ max-width 400px
+ text-align center
+ color #999
+
+ > [data-fa]
+ display block
+ margin-bottom 16px
+ font-size 3em
+ color #ccc
+
+</style>
diff --git a/src/client/app/desktop/views/components/timeline.vue b/src/client/app/desktop/views/components/timeline.vue
index 2db64d6e09..e0215ad1a2 100644
--- a/src/client/app/desktop/views/components/timeline.vue
+++ b/src/client/app/desktop/views/components/timeline.vue
@@ -1,169 +1,93 @@
<template>
<div class="mk-timeline">
- <mk-friends-maker v-if="alone"/>
- <div class="fetching" v-if="fetching">
- <mk-ellipsis-icon/>
- </div>
- <p class="empty" v-if="notes.length == 0 && !fetching">
- %fa:R comments%%i18n:@empty%
- </p>
- <mk-notes :notes="notes" ref="timeline">
- <button slot="footer" @click="more" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }">
- <template v-if="!moreFetching">%i18n:@load-more%</template>
- <template v-if="moreFetching">%fa:spinner .pulse .fw%</template>
- </button>
- </mk-notes>
+ <header>
+ <span :data-is-active="src == 'home'" @click="src = 'home'">%fa:home% ホーム</span>
+ <span :data-is-active="src == 'local'" @click="src = 'local'">%fa:R comments% ローカル</span>
+ <span :data-is-active="src == 'global'" @click="src = 'global'">%fa:globe% グローバル</span>
+ </header>
+ <x-core v-if="src == 'home'" ref="tl" key="home" src="home"/>
+ <x-core v-if="src == 'local'" ref="tl" key="local" src="local"/>
+ <x-core v-if="src == 'global'" ref="tl" key="global" src="global"/>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
-import { url } from '../../../config';
+import XCore from './timeline.core.vue';
export default Vue.extend({
+ components: {
+ XCore
+ },
+
data() {
return {
- fetching: true,
- moreFetching: false,
- existMore: false,
- notes: [],
- connection: null,
- connectionId: null,
- date: null
+ src: 'home'
};
},
- computed: {
- alone(): boolean {
- return (this as any).os.i.followingCount == 0;
- }
- },
-
mounted() {
- this.connection = (this as any).os.stream.getConnection();
- this.connectionId = (this as any).os.stream.use();
-
- this.connection.on('note', this.onNote);
- this.connection.on('follow', this.onChangeFollowing);
- this.connection.on('unfollow', this.onChangeFollowing);
-
document.addEventListener('keydown', this.onKeydown);
window.addEventListener('scroll', this.onScroll);
- this.fetch();
+ console.log(this.$refs.tl);
+
+ (this.$refs.tl as any).$once('loaded', () => {
+ this.$emit('loaded');
+ });
},
beforeDestroy() {
- this.connection.off('note', this.onNote);
- this.connection.off('follow', this.onChangeFollowing);
- this.connection.off('unfollow', this.onChangeFollowing);
- (this as any).os.stream.dispose(this.connectionId);
-
document.removeEventListener('keydown', this.onKeydown);
window.removeEventListener('scroll', this.onScroll);
},
methods: {
- fetch(cb?) {
- this.fetching = true;
-
- (this as any).api('notes/timeline', {
- limit: 11,
- untilDate: this.date ? this.date.getTime() : undefined
- }).then(notes => {
- if (notes.length == 11) {
- notes.pop();
- this.existMore = true;
- }
- this.notes = notes;
- this.fetching = false;
- this.$emit('loaded');
- if (cb) cb();
- });
- },
-
- more() {
- if (this.moreFetching || this.fetching || this.notes.length == 0 || !this.existMore) return;
- this.moreFetching = true;
- (this as any).api('notes/timeline', {
- limit: 11,
- untilId: this.notes[this.notes.length - 1].id
- }).then(notes => {
- if (notes.length == 11) {
- notes.pop();
- } else {
- this.existMore = false;
- }
- this.notes = this.notes.concat(notes);
- this.moreFetching = false;
- });
- },
-
- onNote(note) {
- // サウンドを再生する
- if ((this as any).os.isEnableSounds) {
- const sound = new Audio(`${url}/assets/post.mp3`);
- sound.volume = localStorage.getItem('soundVolume') ? parseInt(localStorage.getItem('soundVolume'), 10) / 100 : 0.5;
- sound.play();
- }
-
- this.notes.unshift(note);
-
- const isTop = window.scrollY > 8;
- if (isTop) this.notes.pop();
- },
-
- onChangeFollowing() {
- this.fetch();
- },
-
onScroll() {
if ((this as any).os.i.clientSettings.fetchOnScroll !== false) {
const current = window.scrollY + window.innerHeight;
- if (current > document.body.offsetHeight - 8) this.more();
+ if (current > document.body.offsetHeight - 8) (this.$refs.tl as any).more();
}
},
onKeydown(e) {
if (e.target.tagName != 'INPUT' && e.target.tagName != 'TEXTAREA') {
if (e.which == 84) { // t
- (this.$refs.timeline as any).focus();
+ (this.$refs.tl as any).focus();
}
}
},
warp(date) {
- this.date = date;
- this.fetch();
+ (this.$refs.tl as any).warp(date);
}
}
});
</script>
<style lang="stylus" scoped>
+@import '~const.styl'
+
.mk-timeline
background #fff
border solid 1px rgba(0, 0, 0, 0.075)
border-radius 6px
- > .mk-friends-maker
+ > header
+ padding 8px 16px
border-bottom solid 1px #eee
- > .fetching
- padding 64px 0
+ > span
+ margin-right 16px
+ line-height 27px
+ font-size 14px
+ color #555
- > .empty
- display block
- margin 0 auto
- padding 32px
- max-width 400px
- text-align center
- color #999
+ &:not([data-is-active])
+ color $theme-color
+ cursor pointer
- > [data-fa]
- display block
- margin-bottom 16px
- font-size 3em
- color #ccc
+ &:hover
+ text-decoration underline
</style>