Merge pull request #694 from h3poteto/iss-677

closes #677 Allow customize unread notification of timelines
This commit is contained in:
AkiraFukushima 2018-11-08 23:01:41 +09:00 committed by GitHub
commit aa79b36125
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
27 changed files with 668 additions and 184 deletions

View File

@ -73,6 +73,7 @@
"reload": "Neu laden"
},
"settings": {
"title": "Settings",
"general": {
"title": "Settings",
"toot": {

View File

@ -1,5 +1,17 @@
{
"side_menu": {
"direct": "Direct messages"
},
"settings": {
"timeline": {
"title": "Timeline",
"unread_notification": {
"title": "Unread Notification",
"description": "Customize unread notifications for each timelines.",
"direct": "Direct Messages",
"local": "Local Timeline",
"public": "Public Timeline"
}
}
}
}
}

View File

@ -90,6 +90,16 @@
"description": "Mark medias as sensitive by default"
}
}
},
"timeline": {
"title": "Timeline",
"unread_notification": {
"title": "Unread Notification",
"description": "Customize unread notifications for each timelines.",
"direct": "Direct Messages",
"local": "Local Timeline",
"public": "Public Timeline"
}
}
},
"preferences": {

View File

@ -1,5 +1,17 @@
{
"side_menu": {
"direct": "Direct messages"
},
"settings": {
"timeline": {
"title": "Timeline",
"unread_notification": {
"title": "Unread Notification",
"description": "Customize unread notifications for each timelines.",
"direct": "Direct Messages",
"local": "Local Timeline",
"public": "Public Timeline"
}
}
}
}
}

View File

@ -47,6 +47,7 @@
"expand": "拡大",
"home": "ホーム",
"notification": "通知",
"direct": "ダイレクトメッセージ",
"favourite": "お気に入り",
"local": "ローカル",
"public": "連合",
@ -75,6 +76,7 @@
"settings": {
"title": "設定",
"general": {
"title": "一般",
"toot": {
"title": "トゥート",
"visibility": {
@ -88,6 +90,16 @@
"description": "メディアを常に閲覧注意として投稿する"
}
}
},
"timeline": {
"title": "タイムライン",
"unread_notification": {
"title": "未読管理",
"description": "未読管理をするタイムラインを設定",
"direct": "ダイレクトメッセージ",
"local": "ローカル",
"public": "連合"
}
}
},
"preferences": {

View File

@ -1,5 +1,17 @@
{
"side_menu": {
"direct": "Direct messages"
},
"settings": {
"timeline": {
"title": "Timeline",
"unread_notification": {
"title": "Unread Notification",
"description": "Customize unread notifications for each timelines.",
"direct": "Direct Messages",
"local": "Local Timeline",
"public": "Public Timeline"
}
}
}
}
}

View File

@ -1,5 +1,17 @@
{
"side_menu": {
"direct": "Direct messages"
},
"settings": {
"timeline": {
"title": "Timeline",
"unread_notification": {
"title": "Unread Notification",
"description": "Customize unread notifications for each timelines.",
"direct": "Direct Messages",
"local": "Local Timeline",
"public": "Public Timeline"
}
}
}
}
}

View File

@ -0,0 +1,11 @@
export default {
Direct: {
default: false
},
Local: {
default: true
},
Public: {
default: false
}
}

View File

@ -17,6 +17,7 @@ import StreamingManager from './streaming_manager'
import Preferences from './preferences'
import Fonts from './fonts'
import Hashtags from './hashtags'
import UnreadNotification from './unread_notification'
import i18n from '../config/i18n'
import Language from '../constants/language'
@ -70,6 +71,13 @@ let hashtagsDB = new Datastore({
autoload: true
})
const unreadNotificationDBPath = process.env.NODE_ENV === 'production'
? userData + '/db/unread_notification.db'
: 'unread_notification.db'
const unreadNotification = new UnreadNotification(unreadNotificationDBPath)
unreadNotification.initialize()
.catch(err => log.error(err))
const preferencesDBPath = process.env.NODE_ENV === 'production'
? userData + './db/preferences.json'
: 'preferences.json'
@ -762,6 +770,32 @@ ipcMain.on('list-fonts', (event, _) => {
})
})
// Unread notifications
ipcMain.on('get-unread-notification', (event, accountID) => {
unreadNotification.findOne({
accountID: accountID
})
.then(doc => {
event.sender.send('response-get-unread-notification', doc)
})
.catch(err => {
console.warn(err)
event.sender.send('error-get-unread-notification', err)
})
})
ipcMain.on('update-unread-notification', (event, obj) => {
const { accountID } = obj
unreadNotification.insertOrUpdate(accountID, obj)
.then(_ => {
event.sender.send('response-update-unread-notification', true)
})
.catch(err => {
console.error(err)
event.sender.send('error-update-unread-notification', err)
})
})
// Application control
ipcMain.on('relaunch', (event, _) => {
app.relaunch()

View File

@ -0,0 +1,63 @@
import empty from 'is-empty'
import Datastore from 'nedb'
export default class UnreadNotification {
constructor (path) {
this.db = new Datastore({
filename: path,
autoload: true
})
}
async initialize () {
await this.updateUnique()
}
updateUnique () {
return new Promise((resolve, reject) => {
// At first, remove old index.
this.db.removeIndex('accountID', (err) => {
if (err) reject(err)
// Add unique index.
this.db.ensureIndex({ fieldName: 'accountID', unique: true, sparse: true }, (err) => {
if (err) reject(err)
resolve(null)
})
})
})
}
insertOrUpdate (accountID, obj) {
return new Promise((resolve, reject) => {
this.db.update(
{
accountID: accountID
},
obj,
{
upsert: true
},
(err, num) => {
if (err) return reject(err)
resolve(num)
})
})
}
findOne (obj) {
return new Promise((resolve, reject) => {
this.db.findOne(obj, (err, doc) => {
if (err) return reject(err)
if (empty(doc)) return reject(new EmptyRecordError('empty'))
resolve(doc)
})
})
}
}
class EmptyRecordError extends Error {
constructor (msg) {
super(msg)
this.name = 'EmptyRecordError'
}
}

View File

@ -23,6 +23,10 @@
<icon name="cog" class="icon" scale="1.3"></icon>
<span>{{ $t('settings.general.title') }}</span>
</el-menu-item>
<el-menu-item :index="`/${id()}/settings/timeline`">
<icon name="align-left" class="icon" scale="1.3"></icon>
<span>{{ $t('settings.timeline.title') }}</span>
</el-menu-item>
</el-menu>
</el-aside>
<el-main>
@ -44,6 +48,7 @@ export default {
})
},
created () {
this.$store.commit('Settings/changeAccountID', this.id())
this.$router.push(`/${this.id()}/settings/general`)
},
methods: {

View File

@ -0,0 +1,105 @@
<template>
<div id="timeline">
<div class="unread-notification section">
<h3>{{ $t('settings.timeline.unread_notification.title') }}</h3>
<p class="description">{{ $t('settings.timeline.unread_notification.description') }}</p>
<table class="table">
<tbody>
<tr>
<td class="title">
{{ $t('settings.timeline.unread_notification.direct') }}
</td>
<td class="status">
<el-switch v-model="direct" />
</td>
</tr>
<tr>
<td class="title">
{{ $t('settings.timeline.unread_notification.local') }}
</td>
<td class="status">
<el-switch v-model="local" />
</td>
</tr>
<tr>
<td class="title">
{{ $t('settings.timeline.unread_notification.public') }}
</td>
<td class="status">
<el-switch v-model="public" />
</td>
</tr>
</tbody>
</table>
</div>
</div>
</template>
<script>
export default {
name: 'Timeline',
computed: {
direct: {
get () {
return this.$store.state.Settings.Timeline.unreadNotification.direct
},
set (value) {
this.$store.dispatch('Settings/Timeline/changeUnreadNotification', {
direct: value
})
}
},
local: {
get () {
return this.$store.state.Settings.Timeline.unreadNotification.local
},
set (value) {
this.$store.dispatch('Settings/Timeline/changeUnreadNotification', {
local: value
})
}
},
public: {
get () {
return this.$store.state.Settings.Timeline.unreadNotification.public
},
set (value) {
this.$store.dispatch('Settings/Timeline/changeUnreadNotification', {
public: value
})
}
}
},
async created () {
await this.$store.dispatch('Settings/Timeline/loadUnreadNotification')
}
}
</script>
<style lang="scss" scoped>
#timeline {
.description {
margin: 32px 0 20px;
}
.section {
margin-bottom: 40px;
}
.table {
tr {
height: 3rem;
}
.title {
width: 200px;
text-align: right;
}
.status {
width: 200px;
text-align: center;
}
}
}
</style>

View File

@ -72,20 +72,12 @@ export default {
window.removeEventListener('dragleave', this.onDragLeave)
window.removeEventListener('dragover', this.onDragOver)
window.removeEventListener('drop', this.handleDrop)
this.$store.dispatch('TimelineSpace/stopUserStreaming')
this.$store.dispatch('TimelineSpace/unbindUserStreaming')
this.$store.dispatch('TimelineSpace/stopDirectMessagesStreaming')
this.$store.dispatch('TimelineSpace/unbindDirectMessagesStreaming')
this.$store.dispatch('TimelineSpace/stopLocalStreaming')
this.$store.dispatch('TimelineSpace/unbindLocalStreaming')
this.$store.dispatch('TimelineSpace/stopStreamings')
},
methods: {
async clear () {
await this.$store.dispatch('TimelineSpace/clearAccount')
await this.$store.commit('TimelineSpace/Contents/Home/clearTimeline')
await this.$store.commit('TimelineSpace/Contents/Local/clearTimeline')
await this.$store.commit('TimelineSpace/Contents/DirectMessages/clearTimeline')
await this.$store.commit('TimelineSpace/Contents/Notifications/clearNotifications')
this.$store.dispatch('TimelineSpace/clearContentsTimelines')
await this.$store.dispatch('TimelineSpace/removeShortcutEvents')
await this.$store.dispatch('TimelineSpace/clearUnread')
return 'clear'
@ -100,44 +92,23 @@ export default {
type: 'error'
})
})
try {
await this.$store.dispatch('TimelineSpace/Contents/Home/fetchTimeline', account)
} catch (err) {
this.$message({
message: this.$t('message.timeline_fetch_error'),
type: 'error'
})
}
try {
await this.$store.dispatch('TimelineSpace/Contents/Notifications/fetchNotifications', account)
} catch (err) {
this.$message({
message: this.$t('message.notification_fetch_error'),
type: 'error'
})
}
try {
await this.$store.dispatch('TimelineSpace/Contents/Local/fetchLocalTimeline', account)
await this.$store.dispatch('TimelineSpace/Contents/DirectMessages/fetchTimeline', account)
} catch (err) {
this.$message({
message: this.$t('message.timeline_fetch_error'),
type: 'error'
})
}
this.$store.dispatch('TimelineSpace/SideMenu/fetchLists', account)
this.$store.dispatch('TimelineSpace/bindUserStreaming', account)
this.$store.dispatch('TimelineSpace/startUserStreaming', account)
.catch(() => {
await this.$store.dispatch('TimelineSpace/loadUnreadNotification', this.$route.params.id)
// Load timelines
await this.$store.dispatch('TimelineSpace/fetchContentsTimelines', account)
.catch(_ => {
this.$message({
message: this.$t('message.start_streaming_error'),
message: this.$t('message.timeline_fetch_error'),
type: 'error'
})
})
this.$store.dispatch('TimelineSpace/bindLocalStreaming', account)
this.$store.dispatch('TimelineSpace/startLocalStreaming', account)
this.$store.dispatch('TimelineSpace/bindDirectMessagesStreaming', account)
this.$store.dispatch('TimelineSpace/startDirectMessagesStreaming', account)
// Bind streamings
await this.$store.dispatch('TimelineSpace/bindStreamings', account)
// Start streamings
this.$store.dispatch('TimelineSpace/startStreamings', account)
this.$store.dispatch('TimelineSpace/fetchEmojis', account)
this.$store.dispatch('TimelineSpace/fetchInstance', account)
},

View File

@ -44,15 +44,18 @@ export default {
}
},
computed: {
...mapState('TimelineSpace/Contents/DirectMessages', {
timeline: state => state.timeline,
lazyLoading: state => state.lazyLoading,
heading: state => state.heading,
unread: state => state.unreadTimeline,
filter: state => state.filter
}),
...mapState({
openSideBar: state => state.TimelineSpace.Contents.SideBar.openSideBar,
backgroundColor: state => state.App.theme.background_color,
startReload: state => state.TimelineSpace.HeaderMenu.reload,
timeline: state => state.TimelineSpace.Contents.DirectMessages.timeline,
lazyLoading: state => state.TimelineSpace.Contents.DirectMessages.lazyLoading,
heading: state => state.TimelineSpace.Contents.DirectMessages.heading,
unread: state => state.TimelineSpace.Contents.DirectMessages.unreadTimeline,
filter: state => state.TimelineSpace.Contents.DirectMessages.filter
unreadNotification: state => state.TimelineSpace.unreadNotification
}),
...mapGetters('TimelineSpace/Modals', [
'modalOpened'
@ -69,19 +72,36 @@ export default {
return currentIndex === -1
}
},
mounted () {
async mounted () {
this.$store.commit('TimelineSpace/changeLoading', true)
this.$store.commit('TimelineSpace/SideMenu/changeUnreadDirectMessagesTimeline', false)
document.getElementById('scrollable').addEventListener('scroll', this.onScroll)
if (!this.unreadNotification.direct) {
await this.initialize()
.catch(_ => {
this.$store.commit('TimelineSpace/changeLoading', false)
})
}
this.$store.commit('TimelineSpace/changeLoading', false)
},
beforeUpdate () {
if (this.$store.state.TimelineSpace.SideMenu.unreadDirectMessagesTimeline && this.heading) {
this.$store.commit('TimelineSpace/SideMenu/changeUnreadDirectMessagesTimeline', false)
}
},
beforeDestroy () {
if (!this.unreadNotification.direct) {
this.$store.dispatch('TimelineSpace/stopDirectMessagesStreaming')
this.$store.dispatch('TimelineSpace/unbindDirectMessagesStreaming')
}
},
destroyed () {
this.$store.commit('TimelineSpace/Contents/DirectMessages/changeHeading', true)
this.$store.commit('TimelineSpace/Contents/DirectMessages/mergeTimeline')
this.$store.commit('TimelineSpace/Contents/DirectMessages/archiveTimeline')
if (!this.unreadNotification.direct) {
this.$store.commit('TimelineSpace/Contents/DirectMessages/clearTimeline')
}
if (document.getElementById('scrollable') !== undefined && document.getElementById('scrollable') !== null) {
document.getElementById('scrollable').removeEventListener('scroll', this.onScroll)
document.getElementById('scrollable').scrollTop = 0
@ -106,6 +126,17 @@ export default {
}
},
methods: {
async initialize () {
await this.$store.dispatch('TimelineSpace/Contents/DirectMessages/fetchTimeline')
.catch(_ => {
this.$message({
message: this.$t('message.timeline_fetch_error'),
type: 'error'
})
})
await this.$store.dispatch('TimelineSpace/bindDirectMessagesStreaming')
this.$store.dispatch('TimelineSpace/startDirectMessagesStreaming')
},
onScroll (event) {
// for lazyLoading
if (((event.target.clientHeight + event.target.scrollTop) >= document.getElementById('directmessages').clientHeight - 10) && !this.lazyloading) {

View File

@ -44,15 +44,18 @@ export default {
}
},
computed: {
...mapState('TimelineSpace/Contents/Local', {
timeline: state => state.timeline,
lazyLoading: state => state.lazyLoading,
heading: state => state.heading,
unread: state => state.unreadTimeline,
filter: state => state.filter
}),
...mapState({
openSideBar: state => state.TimelineSpace.Contents.SideBar.openSideBar,
backgroundColor: state => state.App.theme.background_color,
startReload: state => state.TimelineSpace.HeaderMenu.reload,
timeline: state => state.TimelineSpace.Contents.Local.timeline,
lazyLoading: state => state.TimelineSpace.Contents.Local.lazyLoading,
heading: state => state.TimelineSpace.Contents.Local.heading,
unread: state => state.TimelineSpace.Contents.Local.unreadTimeline,
filter: state => state.TimelineSpace.Contents.Local.filter
unreadNotification: state => state.TimelineSpace.unreadNotification
}),
...mapGetters('TimelineSpace/Modals', [
'modalOpened'
@ -69,19 +72,36 @@ export default {
return currentIndex === -1
}
},
mounted () {
async mounted () {
this.$store.commit('TimelineSpace/changeLoading', true)
this.$store.commit('TimelineSpace/SideMenu/changeUnreadLocalTimeline', false)
document.getElementById('scrollable').addEventListener('scroll', this.onScroll)
if (!this.unreadNotification.local) {
await this.initialize()
.finally(_ => {
this.$store.commit('TimelineSpace/changeLoading', false)
})
}
this.$store.commit('TimelineSpace/changeLoading', false)
},
beforeUpdate () {
if (this.$store.state.TimelineSpace.SideMenu.unreadLocalTimeline && this.heading) {
this.$store.commit('TimelineSpace/SideMenu/changeUnreadLocalTimeline', false)
}
},
beforeDestroy () {
if (!this.unreadNotification.local) {
this.$store.dispatch('TimelineSpace/stopLocalStreaming')
this.$store.dispatch('TimelineSpace/unbindLocalStreaming')
}
},
destroyed () {
this.$store.commit('TimelineSpace/Contents/Local/changeHeading', true)
this.$store.commit('TimelineSpace/Contents/Local/mergeTimeline')
this.$store.commit('TimelineSpace/Contents/Local/archiveTimeline')
if (!this.unreadNotification.local) {
this.$store.commit('TimelineSpace/Contents/Local/clearTimeline')
}
if (document.getElementById('scrollable') !== undefined && document.getElementById('scrollable') !== null) {
document.getElementById('scrollable').removeEventListener('scroll', this.onScroll)
document.getElementById('scrollable').scrollTop = 0
@ -106,6 +126,17 @@ export default {
}
},
methods: {
async initialize () {
await this.$store.dispatch('TimelineSpace/Contents/Local/fetchLocalTimeline')
.catch(_ => {
this.$message({
message: this.$t('message.timeline_fetch_error'),
type: 'error'
})
})
await this.$store.dispatch('TimelineSpace/bindLocalStreaming')
this.$store.dispatch('TimelineSpace/startLocalStreaming')
},
updateToot (message) {
this.$store.commit('TimelineSpace/Contents/Local/updateToot', message)
},

View File

@ -128,15 +128,7 @@ export default {
async reload () {
this.$store.commit('TimelineSpace/changeLoading', true)
try {
const account = await this.reloadable()
await this.$store.dispatch('TimelineSpace/Contents/Notifications/fetchNotifications', account)
.catch(() => {
this.$message({
message: this.$t('message.notification_fetch_error'),
type: 'error'
})
})
await this.reloadable()
this.$store.dispatch('TimelineSpace/Contents/Notifications/resetBadge')
} finally {
this.$store.commit('TimelineSpace/changeLoading', false)

View File

@ -44,15 +44,18 @@ export default {
}
},
computed: {
...mapState('TimelineSpace/Contents/Public', {
timeline: state => state.timeline,
lazyLoading: state => state.lazyLoading,
heading: state => state.heading,
unread: state => state.unreadTimeline,
filter: state => state.filter
}),
...mapState({
openSideBar: state => state.TimelineSpace.Contents.SideBar.openSideBar,
backgroundColor: state => state.App.theme.background_color,
startReload: state => state.TimelineSpace.HeaderMenu.reload,
timeline: state => state.TimelineSpace.Contents.Public.timeline,
lazyLoading: state => state.TimelineSpace.Contents.Public.lazyLoading,
heading: state => state.TimelineSpace.Contents.Public.heading,
unread: state => state.TimelineSpace.Contents.Public.unreadTimeline,
filter: state => state.TimelineSpace.Contents.Public.filter
unreadNotification: state => state.TimelineSpace.unreadNotification
}),
...mapGetters('TimelineSpace/Modals', [
'modalOpened'
@ -69,22 +72,36 @@ export default {
return currentIndex === -1
}
},
created () {
async mounted () {
this.$store.commit('TimelineSpace/changeLoading', true)
this.initialize()
.finally(() => {
this.$store.commit('TimelineSpace/changeLoading', false)
})
this.$store.commit('TimelineSpace/SideMenu/changeUnreadPublicTimeline', false)
document.getElementById('scrollable').addEventListener('scroll', this.onScroll)
if (!this.unreadNotification.public) {
await this.initialize()
.finally(_ => {
this.$store.commit('TimelineSpace/changeLoading', false)
})
}
this.$store.commit('TimelineSpace/changeLoading', false)
},
beforeUpdate () {
if (this.$store.state.TimelineSpace.SideMenu.unreadPublicTimeline && this.heading) {
this.$store.commit('TimelineSpace/SideMenu/changeUnreadPublicTimeline', false)
}
},
beforeDestroy () {
this.$store.dispatch('TimelineSpace/Contents/Public/stopPublicStreaming')
if (!this.unreadNotification.public) {
this.$store.dispatch('TimelineSpace/stopPublicStreaming')
this.$store.dispatch('TimelineSpace/unbindPublicStreaming')
}
},
destroyed () {
this.$store.commit('TimelineSpace/Contents/Public/changeHeading', true)
this.$store.commit('TimelineSpace/Contents/Public/mergeTimeline')
this.$store.commit('TimelineSpace/Contents/Public/archiveTimeline')
this.$store.commit('TimelineSpace/Contents/Public/clearTimeline')
if (!this.unreadNotification.public) {
this.$store.commit('TimelineSpace/Contents/Public/clearTimeline')
}
if (document.getElementById('scrollable') !== undefined && document.getElementById('scrollable') !== null) {
document.getElementById('scrollable').removeEventListener('scroll', this.onScroll)
document.getElementById('scrollable').scrollTop = 0
@ -110,21 +127,15 @@ export default {
},
methods: {
async initialize () {
try {
await this.$store.dispatch('TimelineSpace/Contents/Public/fetchPublicTimeline')
} catch (err) {
this.$message({
message: this.$t('message.timeline_fetch_error'),
type: 'error'
})
}
this.$store.dispatch('TimelineSpace/Contents/Public/startPublicStreaming')
.catch(() => {
await this.$store.dispatch('TimelineSpace/Contents/Public/fetchPublicTimeline')
.catch(_ => {
this.$message({
message: this.$t('message.start_streaming_error'),
message: this.$t('message.timeline_fetch_error'),
type: 'error'
})
})
await this.$store.dispatch('TimelineSpace/bindPublicStreaming')
this.$store.dispatch('TimelineSpace/startPublicStreaming')
},
updateToot (message) {
this.$store.commit('TimelineSpace/Contents/Public/updateToot', message)
@ -154,21 +165,6 @@ export default {
this.$store.commit('TimelineSpace/changeLoading', true)
try {
await this.reloadable()
await this.$store.dispatch('TimelineSpace/Contents/Public/stopPublicStreaming')
await this.$store.dispatch('TimelineSpace/Contents/Public/fetchPublicTimeline')
.catch(() => {
this.$message({
message: this.$t('message.timeline_fetch_error'),
type: 'error'
})
})
this.$store.dispatch('TimelineSpace/Contents/Public/startPublicStreaming')
.catch(() => {
this.$message({
message: this.$t('message.start_streaming_error'),
type: 'error'
})
})
} finally {
this.$store.commit('TimelineSpace/changeLoading', false)
}

View File

@ -68,6 +68,8 @@
<el-menu-item :index="`/${id()}/public`" role="menuitem" :title="$t('side_menu.public')">
<icon name="globe"></icon>
<span>{{ $t("side_menu.public") }}</span>
<el-badge is-dot :hidden="!unreadPublicTimeline">
</el-badge>
</el-menu-item>
<el-menu-item :index="`/${id()}/search`" role="menuitem" :title="$t('side_menu.search')">
<icon name="search"></icon>
@ -115,6 +117,7 @@ export default {
unreadNotifications: state => state.unreadNotifications,
unreadLocalTimeline: state => state.unreadLocalTimeline,
unreadDirectMessagesTimeline: state => state.unreadDirectMessagesTimeline,
unreadPublicTimeline: state => state.unreadPublicTimeline,
lists: state => state.lists,
tags: state => state.tags,
collapse: state => state.collapse

View File

@ -10,17 +10,9 @@ export default {
})
throw err
})
await this.$store.dispatch('TimelineSpace/stopUserStreaming')
await this.$store.dispatch('TimelineSpace/stopLocalStreaming')
await this.$store.dispatch('TimelineSpace/stopDirectMessagesStreaming')
await this.$store.dispatch('TimelineSpace/Contents/Home/fetchTimeline', account)
await this.$store.dispatch('TimelineSpace/Contents/Local/fetchLocalTimeline', account)
await this.$store.dispatch('TimelineSpace/Contents/DirectMessages/fetchTimeline', account)
this.$store.dispatch('TimelineSpace/startUserStreaming', account)
this.$store.dispatch('TimelineSpace/startLocalStreaming', account)
this.$store.dispatch('TimelineSpace/startDirectMessagesStreaming', account)
await this.$store.dispatch('TimelineSpace/stopStreamings', account)
await this.$store.dispatch('TimelineSpace/fetchContentsTimelines', account)
await this.$store.dispatch('TimelineSpace/startStreamings', account)
return account
}
}

View File

@ -60,6 +60,10 @@ export default new Router({
{
path: 'general',
component: require('@/components/Settings/General').default
},
{
path: 'timeline',
component: require('@/components/Settings/Timeline').default
}
]
},

View File

@ -1,8 +1,18 @@
import General from './Settings/General'
import Timeline from './Settings/Timeline'
export default {
namespaced: true,
modules: {
General
General,
Timeline
},
state: {
accountID: null
},
mutations: {
changeAccountID (state, id) {
state.accountID = id
}
}
}

View File

@ -0,0 +1,56 @@
import { ipcRenderer } from 'electron'
import unreadSettings from '~/src/constants/unreadNotification'
export default {
namespaced: true,
state: {
unreadNotification: {
direct: unreadSettings.Direct.default,
local: unreadSettings.Local.default,
public: unreadSettings.Public.default
}
},
mutations: {
updateUnreadNotification (state, settings) {
state.unreadNotification = settings
}
},
actions: {
loadUnreadNotification ({ commit, rootState }) {
return new Promise((resolve, reject) => {
ipcRenderer.once('response-get-unread-notification', (event, settings) => {
ipcRenderer.removeAllListeners('error-get-unread-notification')
commit('updateUnreadNotification', settings)
resolve(settings)
})
ipcRenderer.once('error-get-unread-notification', (event, err) => {
ipcRenderer.removeAllListeners('response-get-unread-notification')
commit('updateUnreadNotification', {
direct: unreadSettings.Direct.default,
local: unreadSettings.Local.default,
public: unreadSettings.Public.default
})
resolve(null)
})
ipcRenderer.send('get-unread-notification', rootState.Settings.accountID)
})
},
changeUnreadNotification ({ dispatch, state, rootState }, timeline) {
const settings = Object.assign({}, state.unreadNotification, timeline, {
accountID: rootState.Settings.accountID
})
return new Promise((resolve, reject) => {
ipcRenderer.once('response-update-unread-notification', (event, _) => {
ipcRenderer.removeAllListeners('error-update-unread-notification')
dispatch('loadUnreadNotification')
resolve(settings)
})
ipcRenderer.once('error-update-unread-notification', (event, err) => {
ipcRenderer.removeAllListeners('response-update-unread-notification')
reject(err)
})
ipcRenderer.send('update-unread-notification', settings)
})
}
}
}

View File

@ -5,6 +5,7 @@ import HeaderMenu from './TimelineSpace/HeaderMenu'
import Modals from './TimelineSpace/Modals'
import Contents from './TimelineSpace/Contents'
import router from '../router'
import unreadSettings from '~/src/constants/unreadNotification'
const TimelineSpace = {
namespaced: true,
@ -22,7 +23,12 @@ const TimelineSpace = {
},
loading: false,
emojis: [],
tootMax: 500
tootMax: 500,
unreadNotification: {
direct: unreadSettings.Direct.default,
local: unreadSettings.Local.default,
public: unreadSettings.Public.default
}
},
mutations: {
updateAccount (state, account) {
@ -45,9 +51,15 @@ const TimelineSpace = {
} else {
state.tootMax = 500
}
},
updateUnreadNotification (state, settings) {
state.unreadNotification = settings
}
},
actions: {
// -------------------------------------------------
// Accounts
// -------------------------------------------------
localAccount ({ dispatch, commit }, id) {
return new Promise((resolve, reject) => {
ipcRenderer.send('get-local-account', id)
@ -87,6 +99,131 @@ const TimelineSpace = {
})
})
},
async clearAccount ({ commit }) {
commit(
'updateAccount',
{
domain: '',
_id: '',
username: ''
}
)
return 'clearAccount'
},
// -----------------------------------------------
// Shortcuts
// -----------------------------------------------
watchShortcutEvents ({ commit, dispatch }) {
ipcRenderer.on('CmdOrCtrl+N', () => {
dispatch('TimelineSpace/Modals/NewToot/openModal', {}, { root: true })
})
ipcRenderer.on('CmdOrCtrl+K', () => {
commit('TimelineSpace/Modals/Jump/changeModal', true, { root: true })
})
},
async removeShortcutEvents () {
ipcRenderer.removeAllListeners('CmdOrCtrl+N')
ipcRenderer.removeAllListeners('CmdOrCtrl+K')
return 'removeShortcutEvents'
},
/**
* clearUnread
*/
async clearUnread ({ dispatch }) {
dispatch('TimelineSpace/SideMenu/clearUnread', {}, { root: true })
},
/**
* fetchEmojis
*/
async fetchEmojis ({ commit }, account) {
const data = await Mastodon.get('/custom_emojis', {}, account.baseURL + '/api/v1')
commit('updateEmojis', data)
return data
},
/**
* fetchInstance
*/
async fetchInstance ({ commit }, account) {
const data = await Mastodon.get('/instance', {}, account.baseURL + '/api/v1')
commit('updateTootMax', data.max_toot_chars)
return data
},
loadUnreadNotification ({ commit, rootState }, accountID) {
return new Promise((resolve, reject) => {
ipcRenderer.once('response-get-unread-notification', (event, settings) => {
ipcRenderer.removeAllListeners('error-get-unread-notification')
commit('updateUnreadNotification', settings)
resolve(settings)
})
ipcRenderer.once('error-get-unread-notification', (event, err) => {
ipcRenderer.removeAllListeners('response-get-unread-notification')
commit('updateUnreadNotification', {
direct: unreadSettings.Direct.default,
local: unreadSettings.Local.default,
public: unreadSettings.Public.default
})
resolve(null)
})
ipcRenderer.send('get-unread-notification', accountID)
})
},
async fetchContentsTimelines ({ dispatch, state }, account) {
await dispatch('TimelineSpace/Contents/Home/fetchTimeline', account, { root: true })
await dispatch('TimelineSpace/Contents/Notifications/fetchNotifications', account, { root: true })
if (state.unreadNotification.direct) {
await dispatch('TimelineSpace/Contents/DirectMessages/fetchTimeline', {}, { root: true })
}
if (state.unreadNotification.local) {
await dispatch('TimelineSpace/Contents/Local/fetchLocalTimeline', {}, { root: true })
}
if (state.unreadNotification.public) {
await dispatch('TimelineSpace/Contents/Public/fetchPublicTimeline', {}, { root: true })
}
},
clearContentsTimelines ({ commit }) {
commit('TimelineSpace/Contents/Home/clearTimeline', {}, { root: true })
commit('TimelineSpace/Contents/Local/clearTimeline', {}, { root: true })
commit('TimelineSpace/Contents/DirectMessages/clearTimeline', {}, { root: true })
commit('TimelineSpace/Contents/Notifications/clearNotifications', {}, { root: true })
commit('TimelineSpace/Contents/Public/clearTimeline', {}, { root: true })
},
bindStreamings ({ dispatch, state }, account) {
dispatch('bindUserStreaming', account)
if (state.unreadNotification.direct) {
dispatch('bindDirectMessagesStreaming')
}
if (state.unreadNotification.local) {
dispatch('bindLocalStreaming')
}
if (state.unreadNotification.public) {
dispatch('bindPublicStreaming')
}
},
startStreamings ({ dispatch, state }, account) {
dispatch('startUserStreaming', account)
if (state.unreadNotification.direct) {
dispatch('startDirectMessagesStreaming')
}
if (state.unreadNotification.local) {
dispatch('startLocalStreaming')
}
if (state.unreadNotification.public) {
dispatch('startPublicStreaming')
}
},
stopStreamings ({ dispatch }, account) {
dispatch('stopUserStreaming')
dispatch('stopDirectMessagesStreaming')
dispatch('stopLocalStreaming')
dispatch('stopPublicStreaming')
dispatch('unbindUserStreaming')
dispatch('unbindDirectMessagesStreaming')
dispatch('unbindLocalStreaming')
dispatch('unbindPublicStreaming')
},
// ------------------------------------------------
// Each streaming methods
// ------------------------------------------------
bindUserStreaming ({ commit, rootState }, account) {
ipcRenderer.on('update-start-user-streaming', (event, update) => {
commit('TimelineSpace/Contents/Home/appendTimeline', update, { root: true })
@ -127,14 +264,31 @@ const TimelineSpace = {
commit('TimelineSpace/SideMenu/changeUnreadLocalTimeline', true, { root: true })
})
},
startLocalStreaming (_, account) {
startLocalStreaming ({ state }) {
return new Promise((resolve, reject) => {
ipcRenderer.send('start-local-streaming', account)
ipcRenderer.send('start-local-streaming', state.account)
ipcRenderer.once('error-start-local-streaming', (event, err) => {
reject(err)
})
})
},
bindPublicStreaming ({ commit, rootState }) {
ipcRenderer.on('update-start-public-streaming', (event, update) => {
commit('TimelineSpace/Contents/Public/appendTimeline', update, { root: true })
if (rootState.TimelineSpace.Contents.Public.heading && Math.random() > 0.8) {
commit('TimelineSpace/Contents/Public/archiveTimeline', {}, { root: true })
}
})
commit('TimelineSpace/SideMenu/changeUnreadPublicTimeline', true, { root: true })
},
startPublicStreaming ({ state }) {
return new Promise((resolve, reject) => {
ipcRenderer.send('start-public-streaming', state.account)
ipcRenderer.once('error-start-public-streaming', (event, err) => {
reject(err)
})
})
},
bindDirectMessagesStreaming ({ commit, rootState }) {
ipcRenderer.on('update-start-directmessages-streaming', (event, update) => {
commit('TimelineSpace/Contents/DirectMessages/appendTimeline', update, { root: true })
@ -144,9 +298,9 @@ const TimelineSpace = {
commit('TimelineSpace/SideMenu/changeUnreadDirectMessagesTimeline', true, { root: true })
})
},
startDirectMessagesStreaming (_, account) {
startDirectMessagesStreaming ({ state }) {
return new Promise((resolve, reject) => {
ipcRenderer.send('start-directmessages-streaming', account)
ipcRenderer.send('start-directmessages-streaming', state.account)
ipcRenderer.once('error-start-directmessages-streaming', (event, err) => {
reject(err)
})
@ -167,49 +321,19 @@ const TimelineSpace = {
stopLocalStreaming () {
ipcRenderer.send('stop-local-streaming')
},
unbindPublicStreaming () {
ipcRenderer.removeAllListeners('error-start-public-streaming')
ipcRenderer.removeAllListeners('update-start-public-streaming')
},
stopPublicStreaming () {
ipcRenderer.send('stop-public-streaming')
},
unbindDirectMessagesStreaming () {
ipcRenderer.removeAllListeners('error-start-directmessages-streaming')
ipcRenderer.removeAllListeners('update-start-directmessages-streaming')
},
stopDirectMessagesStreaming () {
ipcRenderer.send('stop-drectmessages-streaming')
},
watchShortcutEvents ({ commit, dispatch }) {
ipcRenderer.on('CmdOrCtrl+N', () => {
dispatch('TimelineSpace/Modals/NewToot/openModal', {}, { root: true })
})
ipcRenderer.on('CmdOrCtrl+K', () => {
commit('TimelineSpace/Modals/Jump/changeModal', true, { root: true })
})
},
async removeShortcutEvents () {
ipcRenderer.removeAllListeners('CmdOrCtrl+N')
ipcRenderer.removeAllListeners('CmdOrCtrl+K')
return 'removeShortcutEvents'
},
async clearAccount ({ commit }) {
commit(
'updateAccount',
{
domain: '',
_id: '',
username: ''
}
)
return 'clearAccount'
},
async clearUnread ({ dispatch }) {
dispatch('TimelineSpace/SideMenu/clearUnread', {}, { root: true })
},
async fetchEmojis ({ commit }, account) {
const data = await Mastodon.get('/custom_emojis', {}, account.baseURL + '/api/v1')
commit('updateEmojis', data)
return data
},
async fetchInstance ({ commit }, account) {
const data = await Mastodon.get('/instance', {}, account.baseURL + '/api/v1')
commit('updateTootMax', data.max_toot_chars)
return data
}
}
}

View File

@ -71,7 +71,7 @@ const DirectMessages = {
}
},
actions: {
fetchTimeline ({ state, commit, rootState }, account) {
fetchTimeline ({ state, commit, rootState }) {
const client = new Mastodon(
rootState.TimelineSpace.account.accessToken,
rootState.TimelineSpace.account.baseURL + '/api/v1'

View File

@ -70,10 +70,10 @@ const Local = {
}
},
actions: {
fetchLocalTimeline ({ commit }, account) {
fetchLocalTimeline ({ commit, rootState }) {
const client = new Mastodon(
account.accessToken,
account.baseURL + '/api/v1'
rootState.TimelineSpace.account.accessToken,
rootState.TimelineSpace.account.baseURL + '/api/v1'
)
return client.get('/timelines/public', { limit: 40, local: true })
.then(res => {

View File

@ -1,4 +1,3 @@
import { ipcRenderer } from 'electron'
import Mastodon from 'megalodon'
const Public = {
@ -81,25 +80,6 @@ const Public = {
commit('updateTimeline', res.data)
})
},
startPublicStreaming ({ state, commit, rootState }) {
ipcRenderer.on('update-start-public-streaming', (event, update) => {
commit('appendTimeline', update)
if (state.heading && Math.random() > 0.8) {
commit('archiveTimeline')
}
})
return new Promise((resolve, reject) => {
ipcRenderer.send('start-public-streaming', rootState.TimelineSpace.account)
ipcRenderer.once('error-start-public-streaming', (event, err) => {
reject(err)
})
})
},
stopPublicStreaming ({ commit }) {
ipcRenderer.removeAllListeners('error-start-public-streaming')
ipcRenderer.removeAllListeners('update-start-public-streaming')
ipcRenderer.send('stop-public-streaming')
},
lazyFetchTimeline ({ state, commit, rootState }, last) {
if (last === undefined || last === null) {
return Promise.resolve(null)

View File

@ -8,6 +8,7 @@ const SideMenu = {
unreadNotifications: false,
unreadLocalTimeline: false,
unreadDirectMessagesTimeline: false,
unreadPublicTimeline: false,
lists: [],
tags: [],
collapse: false
@ -25,6 +26,9 @@ const SideMenu = {
changeUnreadDirectMessagesTimeline (state, value) {
state.unreadDirectMessagesTimeline = value
},
changeUnreadPublicTimeline (state, value) {
state.unreadPublicTimeline = value
},
updateLists (state, lists) {
state.lists = lists
},
@ -53,6 +57,7 @@ const SideMenu = {
commit('changeUnreadNotifications', false)
commit('changeUnreadLocalTimeline', false)
commit('changeUnreadDirectMessagesTimeline', false)
commit('changeUnreadPublicTimeline', false)
},
changeCollapse ({ commit }, value) {
commit('changeCollapse', value)