Merge pull request #23 from h3poteto/iss-6
refs #6 Call streaming and display home timeline
This commit is contained in:
commit
333a2be131
|
@ -9803,6 +9803,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"moment": {
|
||||
"version": "2.21.0",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.21.0.tgz",
|
||||
"integrity": "sha512-TCZ36BjURTeFTM/CwRcViQlfkMvL1/vFISuNLO5GkcVm1+QHfbSiNqZuWeMFjj1/3+uAjXswgRk30j1kkLYJBQ=="
|
||||
},
|
||||
"move-concurrently": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",
|
||||
|
|
|
@ -62,6 +62,7 @@
|
|||
"google-fonts-webpack-plugin": "^0.4.4",
|
||||
"is-empty": "^1.2.0",
|
||||
"mastodon-api": "^1.3.0",
|
||||
"moment": "^2.21.0",
|
||||
"nedb": "^1.8.0",
|
||||
"vue": "^2.3.3",
|
||||
"vue-awesome": "^2.3.5",
|
||||
|
|
|
@ -7,6 +7,7 @@ import empty from 'is-empty'
|
|||
|
||||
import Authentication from './auth'
|
||||
import Account from './account'
|
||||
import Streaming from './streaming'
|
||||
|
||||
/**
|
||||
* Set `__static` path to static files in production
|
||||
|
@ -126,6 +127,36 @@ ipcMain.on('get-local-account', (event, id) => {
|
|||
})
|
||||
})
|
||||
|
||||
// streaming
|
||||
let userStreaming = null
|
||||
|
||||
ipcMain.on('start-user-streaming', (event, ac) => {
|
||||
const account = new Account(db)
|
||||
account.getAccount(ac._id)
|
||||
.catch((err) => {
|
||||
event.sender.send('error-start-user-streaming', err)
|
||||
})
|
||||
.then((account) => {
|
||||
userStreaming = new Streaming(account)
|
||||
userStreaming.startUserStreaming(
|
||||
(update) => {
|
||||
event.sender.send('update-start-user-streaming', update)
|
||||
},
|
||||
(notification) => {
|
||||
event.sender.send('notification-start-user-streaming', notification)
|
||||
},
|
||||
(err) => {
|
||||
event.sender.send('error-start-user-streaming', err)
|
||||
}
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
ipcMain.on('stop-user-streaming', (event, _) => {
|
||||
userStreaming.stop()
|
||||
userStreaming = null
|
||||
})
|
||||
|
||||
/**
|
||||
* Auto Updater
|
||||
*
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
import Mastodon from 'mastodon-api'
|
||||
|
||||
export default class Streaming {
|
||||
constructor (account) {
|
||||
this.account = account
|
||||
this.client = new Mastodon(
|
||||
{
|
||||
access_token: account.accessToken,
|
||||
api_url: account.baseURL + '/api/v1'
|
||||
}
|
||||
)
|
||||
this.listener = null
|
||||
}
|
||||
|
||||
startUserStreaming (updateCallback, notificationCallback, errCallback) {
|
||||
this.listener = this.client.stream('/streaming/user')
|
||||
|
||||
this.listener.on('message', (msg) => {
|
||||
switch (msg.event) {
|
||||
case 'update':
|
||||
updateCallback(msg.data)
|
||||
break
|
||||
case 'notification':
|
||||
notificationCallback(msg.data)
|
||||
break
|
||||
default:
|
||||
console.log(msg)
|
||||
break
|
||||
}
|
||||
})
|
||||
|
||||
this.listener.on('error', (err) => {
|
||||
errCallback(err)
|
||||
})
|
||||
}
|
||||
|
||||
stop () {
|
||||
this.listener.stop()
|
||||
}
|
||||
}
|
|
@ -65,6 +65,10 @@ html, body, #app, #global_header {
|
|||
margin: 0;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#global_header {
|
||||
.account-menu {
|
||||
height: 100%;
|
||||
|
|
|
@ -14,7 +14,21 @@ export default {
|
|||
name: 'timeline-space',
|
||||
components: { SideMenu },
|
||||
created () {
|
||||
console.log(this.$route.params.id)
|
||||
this.$store.dispatch('TimelineSpace/fetchAccount', this.$route.params.id)
|
||||
.then((account) => {
|
||||
this.$store.dispatch('TimelineSpace/fetchHomeTimeline', account)
|
||||
this.$store.dispatch('TimelineSpace/startUserStreaming', account)
|
||||
this.$store.dispatch('TimelineSpace/username', account)
|
||||
})
|
||||
.catch(() => {
|
||||
this.$message({
|
||||
message: 'Could not find account',
|
||||
type: 'error'
|
||||
})
|
||||
})
|
||||
},
|
||||
beforeDestroy () {
|
||||
this.$store.dispatch('TimelineSpace/stopUserStreaming')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -1,11 +1,28 @@
|
|||
<template>
|
||||
<div id="home">
|
||||
home
|
||||
<div class="home-timeline" v-for="message in timeline" v-bind:key="message.id">
|
||||
<toot :message="message"></toot>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
import Toot from './Toot'
|
||||
|
||||
export default {
|
||||
name: 'home'
|
||||
name: 'home',
|
||||
components: { Toot },
|
||||
computed: {
|
||||
...mapState({
|
||||
timeline: state => state.TimelineSpace.homeTimeline
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.home-timeline {
|
||||
margin-left: 16px;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -44,22 +44,10 @@ export default {
|
|||
name: 'side-menu',
|
||||
computed: {
|
||||
...mapState({
|
||||
account: state => state.TimelineSpace.SideMenu.account,
|
||||
username: state => state.TimelineSpace.SideMenu.username
|
||||
account: state => state.TimelineSpace.account,
|
||||
username: state => state.TimelineSpace.username
|
||||
})
|
||||
},
|
||||
created () {
|
||||
this.$store.dispatch('TimelineSpace/SideMenu/fetchAccount', this.$route.params.id)
|
||||
.then((account) => {
|
||||
this.$store.dispatch('TimelineSpace/SideMenu/username', account)
|
||||
})
|
||||
.catch(() => {
|
||||
this.$message({
|
||||
message: 'Could not find account',
|
||||
type: 'error'
|
||||
})
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
id () {
|
||||
return this.$route.params.id
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
<template>
|
||||
<div class="toot">
|
||||
<div class="icon">
|
||||
<img :src="message.account.avatar" />
|
||||
</div>
|
||||
<div class="detail">
|
||||
<div class="toot-header">
|
||||
<div class="user">
|
||||
{{ message.account.display_name }}
|
||||
</div>
|
||||
<div class="timestamp">
|
||||
{{ parseDatetime(message.created_at) }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="content" v-html="message.content"></div>
|
||||
<div class="tool-box">
|
||||
<el-button type="text"><icon name="reply" scale="0.9"></icon></el-button>
|
||||
<el-button type="text"><icon name="retweet" scale="0.9"></icon></el-button>
|
||||
<el-button type="text"><icon name="star" scale="0.9"></icon></el-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
<div class="fill-line"></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import moment from 'moment'
|
||||
|
||||
export default {
|
||||
name: 'toot',
|
||||
props: ['message'],
|
||||
methods: {
|
||||
parseDatetime (datetime) {
|
||||
return moment(datetime).format('YYYY-MM-DD HH:mm:ss')
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.fill-line {
|
||||
height: 1px;
|
||||
background-color: #f2f6fc;
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
.toot {
|
||||
.icon {
|
||||
float: left;
|
||||
|
||||
img {
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.detail {
|
||||
margin-left: 42px;
|
||||
margin-right: 8px;
|
||||
margin-top: 8px;
|
||||
|
||||
.toot-header {
|
||||
.user {
|
||||
float: left;
|
||||
font-weight: 800;
|
||||
color: #303133;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.timestamp {
|
||||
font-size: 14px;
|
||||
text-align: right;
|
||||
width: 100%;
|
||||
color: #909399;
|
||||
}
|
||||
}
|
||||
|
||||
.content {
|
||||
font-size: 14px;
|
||||
color: #303133;
|
||||
margin: 4px 0 8px;
|
||||
}
|
||||
|
||||
.tool-box {
|
||||
button {
|
||||
margin: 0 8px;
|
||||
padding: 0;
|
||||
color: #909399;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -19,7 +19,6 @@ const GlobalHeader = {
|
|||
})
|
||||
ipcRenderer.once('response-list-accounts', (event, accounts) => {
|
||||
commit('updateAccounts', accounts)
|
||||
console.log(accounts)
|
||||
resolve(accounts)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,9 +1,102 @@
|
|||
import { ipcRenderer } from 'electron'
|
||||
import Mastodon from 'mastodon-api'
|
||||
import SideMenu from './TimelineSpace/SideMenu'
|
||||
|
||||
const TimelineSpace = {
|
||||
namespaced: true,
|
||||
modules: {
|
||||
SideMenu
|
||||
},
|
||||
state: {
|
||||
account: {
|
||||
domain: '',
|
||||
id: ''
|
||||
},
|
||||
username: '',
|
||||
homeTimeline: [],
|
||||
notification: []
|
||||
},
|
||||
mutations: {
|
||||
updateAccount (state, account) {
|
||||
state.account = account
|
||||
},
|
||||
updateUsername (state, username) {
|
||||
state.username = username
|
||||
},
|
||||
appendHomeTimeline (state, update) {
|
||||
state.homeTimeline = [update].concat(state.homeTimeline)
|
||||
},
|
||||
appendNotification (state, notification) {
|
||||
state.notification = [notification].concat(state.notification)
|
||||
},
|
||||
insertHomeTimeline (state, messages) {
|
||||
state.homeTimeline = state.homeTimeline.concat(messages)
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
fetchAccount ({ commit }, id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
ipcRenderer.send('get-local-account', id)
|
||||
ipcRenderer.once('error-get-local-account', (event, err) => {
|
||||
// TODO: handle error
|
||||
console.log(err)
|
||||
reject(err)
|
||||
})
|
||||
ipcRenderer.once('response-get-local-account', (event, account) => {
|
||||
commit('updateAccount', account)
|
||||
resolve(account)
|
||||
})
|
||||
})
|
||||
},
|
||||
username ({ commit }, account) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const client = new Mastodon(
|
||||
{
|
||||
access_token: account.accessToken,
|
||||
api_url: account.baseURL + '/api/v1'
|
||||
|
||||
})
|
||||
client.get('/accounts/verify_credentials', {})
|
||||
.then((res) => {
|
||||
commit('updateUsername', res.data.username)
|
||||
resolve(res)
|
||||
})
|
||||
})
|
||||
},
|
||||
startUserStreaming ({ commit }, account) {
|
||||
ipcRenderer.send('start-user-streaming', account)
|
||||
// TODO: when get notification, create notify and display badge in sidemenu
|
||||
ipcRenderer.once('error-start-userstreaming', (event, err) => {
|
||||
console.log(err)
|
||||
})
|
||||
ipcRenderer.on('update-start-user-streaming', (event, update) => {
|
||||
commit('appendHomeTimeline', update)
|
||||
})
|
||||
ipcRenderer.on('notification-start-user-streaming', (event, notification) => {
|
||||
commit('appendNotification', notification)
|
||||
})
|
||||
},
|
||||
stopUserStreaming ({ commit }) {
|
||||
ipcRenderer.send('stop-user-streaming')
|
||||
},
|
||||
fetchHomeTimeline ({ commit }, account) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const client = new Mastodon(
|
||||
{
|
||||
access_token: account.accessToken,
|
||||
api_url: account.baseURL + '/api/v1'
|
||||
}
|
||||
)
|
||||
client.get('/timelines/home', { limit: 40 })
|
||||
.then((res) => {
|
||||
commit('insertHomeTimeline', res.data)
|
||||
resolve()
|
||||
})
|
||||
.catch((err) => {
|
||||
reject(err)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,54 +1,8 @@
|
|||
import { ipcRenderer } from 'electron'
|
||||
import Mastodon from 'mastodon-api'
|
||||
|
||||
const SideMenu = {
|
||||
namespaced: true,
|
||||
state: {
|
||||
account: {
|
||||
domain: '',
|
||||
id: ''
|
||||
},
|
||||
username: ''
|
||||
},
|
||||
mutations: {
|
||||
updateAccount (state, account) {
|
||||
state.account = account
|
||||
},
|
||||
updateUsername (state, username) {
|
||||
state.username = username
|
||||
}
|
||||
},
|
||||
actions: {
|
||||
fetchAccount ({ commit }, id) {
|
||||
return new Promise((resolve, reject) => {
|
||||
ipcRenderer.send('get-local-account', id)
|
||||
ipcRenderer.once('error-get-local-account', (event, err) => {
|
||||
// TODO: handle error
|
||||
console.log(err)
|
||||
reject(err)
|
||||
})
|
||||
ipcRenderer.once('response-get-local-account', (event, account) => {
|
||||
commit('updateAccount', account)
|
||||
resolve(account)
|
||||
})
|
||||
})
|
||||
},
|
||||
username ({ commit }, account) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const client = new Mastodon(
|
||||
{
|
||||
access_token: account.accessToken,
|
||||
api_url: account.baseURL + '/api/v1'
|
||||
|
||||
})
|
||||
client.get('/accounts/verify_credentials', {})
|
||||
.then((res) => {
|
||||
commit('updateUsername', res.data.username)
|
||||
resolve(res)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
state: {},
|
||||
mutations: {},
|
||||
actions: {}
|
||||
}
|
||||
|
||||
export default SideMenu
|
||||
|
|
Loading…
Reference in New Issue