diff --git a/src/client/app/common/define-widget.ts b/src/client/app/common/define-widget.ts index 7b98c0903..0b2bc3656 100644 --- a/src/client/app/common/define-widget.ts +++ b/src/client/app/common/define-widget.ts @@ -18,61 +18,65 @@ export default function(data: { default: false } }, + computed: { id(): string { return this.widget.id; + }, + + props(): T { + return this.widget.data; } }, + data() { return { - props: data.props ? data.props() : {} as T, - bakedOldProps: null, - preventSave: false + bakedOldProps: null }; }, + created() { - if (this.props) { - Object.keys(this.props).forEach(prop => { - if (this.widget.data.hasOwnProperty(prop)) { - this.props[prop] = this.widget.data[prop]; - } - }); - } + this.mergeProps(); + + this.$watch('props', () => { + this.mergeProps(); + }); this.bakeProps(); + }, - this.$watch('props', newProps => { - if (this.preventSave) { - this.preventSave = false; - this.bakeProps(); - return; + methods: { + bakeProps() { + this.bakedOldProps = JSON.stringify(this.props); + }, + + mergeProps() { + if (data.props) { + const defaultProps = data.props(); + Object.keys(defaultProps).forEach(prop => { + if (!this.props.hasOwnProperty(prop)) { + Vue.set(this.props, prop, defaultProps[prop]); + } + }); } - if (this.bakedOldProps == JSON.stringify(newProps)) return; + }, + + save() { + if (this.bakedOldProps == JSON.stringify(this.props)) return; this.bakeProps(); if (this.isMobile) { (this as any).api('i/update_mobile_home', { id: this.id, - data: newProps - }).then(() => { - (this as any).os.i.clientSettings.mobileHome.find(w => w.id == this.id).data = newProps; + data: this.props }); } else { (this as any).api('i/update_home', { id: this.id, - data: newProps - }).then(() => { - (this as any).os.i.clientSettings.home.find(w => w.id == this.id).data = newProps; + data: this.props }); } - }, { - deep: true - }); - }, - methods: { - bakeProps() { - this.bakedOldProps = JSON.stringify(this.props); } } }); diff --git a/src/client/app/common/mios.ts b/src/client/app/common/mios.ts index 4e471cf96..7dcae4794 100644 --- a/src/client/app/common/mios.ts +++ b/src/client/app/common/mios.ts @@ -3,6 +3,7 @@ import { EventEmitter } from 'eventemitter3'; import * as merge from 'object-assign-deep'; import * as uuid from 'uuid'; +import initStore from '../store'; import { hostname, apiUrl, swPublickey, version, lang, googleMapsApiKey } from '../config'; import Progress from './scripts/loading'; import Connection from './scripts/streaming/stream'; @@ -16,16 +17,6 @@ import Err from '../common/views/components/connect-failed.vue'; import { LocalTimelineStreamManager } from './scripts/streaming/local-timeline'; import { GlobalTimelineStreamManager } from './scripts/streaming/global-timeline'; -const defaultSettings = { - fetchOnScroll: true, - showMaps: true, - showPostFormOnTopOfTl: false, - gradientWindowHeader: false, - showReplyTarget: true, - showMyRenotes: true, - showRenotedMyNotes: true -}; - //#region api requests let spinner = null; let pending = 0; @@ -117,6 +108,8 @@ export default class MiOS extends EventEmitter { return localStorage.getItem('enableSounds') == 'true'; } + public store: ReturnType; + public apis: API; /** @@ -232,6 +225,11 @@ export default class MiOS extends EventEmitter { console.error.apply(null, args); } + public bakeMe() { + // ローカルストレージにキャッシュ + localStorage.setItem('me', JSON.stringify(this.i)); + } + public signout() { localStorage.removeItem('me'); document.cookie = `i=; domain=${hostname}; expires=Thu, 01 Jan 1970 00:00:01 GMT;`; @@ -243,6 +241,8 @@ export default class MiOS extends EventEmitter { * @param callback A function that call when initialized */ public async init(callback) { + this.store = initStore(this); + //#region Init stream managers this.streams.serverStream = new ServerStreamManager(this); @@ -307,16 +307,11 @@ export default class MiOS extends EventEmitter { // フェッチが完了したとき const fetched = me => { - if (me) { - // デフォルトの設定をマージ - me.clientSettings = Object.assign(defaultSettings, me.clientSettings); - - // ローカルストレージにキャッシュ - localStorage.setItem('me', JSON.stringify(me)); - } - this.i = me; + // ローカルストレージにキャッシュ + this.bakeMe(); + this.emit('signedin'); // Finish init @@ -333,6 +328,14 @@ export default class MiOS extends EventEmitter { // Get cached account data const cachedMe = JSON.parse(localStorage.getItem('me')); + //#region キャッシュされた設定を復元 + const cachedSettings = JSON.parse(localStorage.getItem('settings')); + + if (cachedSettings) { + this.store.commit('settings/init', cachedSettings); + } + //#endregion + // キャッシュがあったとき if (cachedMe) { if (cachedMe.token == null) { @@ -346,12 +349,25 @@ export default class MiOS extends EventEmitter { // 後から新鮮なデータをフェッチ fetchme(cachedMe.token, freshData => { merge(cachedMe, freshData); + + this.store.commit('settings/init', freshData.clientSettings); }); } else { // Get token from cookie const i = (document.cookie.match(/i=(!\w+)/) || [null, null])[1]; - fetchme(i, fetched); + fetchme(i, me => { + if (me) { + Object.entries(me.clientSettings).forEach(([key, value]) => { + this.store.commit('settings/set', { key, value }); + }); + + fetched(me); + } else { + // Finish init + callback(); + } + }); } } @@ -456,7 +472,7 @@ export default class MiOS extends EventEmitter { }; const promise = new Promise((resolve, reject) => { - const viaStream = this.stream.hasConnection && + const viaStream = this.stream && this.stream.hasConnection && (localStorage.getItem('apiViaStream') ? localStorage.getItem('apiViaStream') == 'true' : true); if (viaStream) { diff --git a/src/client/app/common/scripts/streaming/home.ts b/src/client/app/common/scripts/streaming/home.ts index 73f2c5302..ddb0d4820 100644 --- a/src/client/app/common/scripts/streaming/home.ts +++ b/src/client/app/common/scripts/streaming/home.ts @@ -25,10 +25,31 @@ export class HomeStream extends Stream { console.log('I updated:', i); } merge(me, i); + + // キャッシュ更新 + os.bakeMe(); + }); + + this.on('clientSettingUpdated', x => { + os.store.commit('settings/set', { + key: x.key, + value: x.value + }); + }); + + this.on('home_updated', x => { + if (x.home) { + os.store.commit('settings/setHome', x.home); + } else { + os.store.commit('settings/setHomeWidget', { + id: x.id, + data: x.data + }); + } }); // トークンが再生成されたとき - // このままではAPIが利用できないので強制的にサインアウトさせる + // このままではMisskeyが利用できないので強制的にサインアウトさせる this.on('my_token_regenerated', () => { alert('%i18n:!common.my-token-regenerated%'); os.signout(); diff --git a/src/client/app/common/views/components/avatar.vue b/src/client/app/common/views/components/avatar.vue new file mode 100644 index 000000000..5aac9c8ba --- /dev/null +++ b/src/client/app/common/views/components/avatar.vue @@ -0,0 +1,38 @@ + + + + + diff --git a/src/client/app/common/views/components/index.ts b/src/client/app/common/views/components/index.ts index 6bfe43a80..69fed00c7 100644 --- a/src/client/app/common/views/components/index.ts +++ b/src/client/app/common/views/components/index.ts @@ -3,6 +3,7 @@ import Vue from 'vue'; import signin from './signin.vue'; import signup from './signup.vue'; import forkit from './forkit.vue'; +import avatar from './avatar.vue'; import nav from './nav.vue'; import noteHtml from './note-html'; import poll from './poll.vue'; @@ -28,6 +29,7 @@ import welcomeTimeline from './welcome-timeline.vue'; Vue.component('mk-signin', signin); Vue.component('mk-signup', signup); Vue.component('mk-forkit', forkit); +Vue.component('mk-avatar', avatar); Vue.component('mk-nav', nav); Vue.component('mk-note-html', noteHtml); Vue.component('mk-poll', poll); diff --git a/src/client/app/common/views/components/messaging-room.message.vue b/src/client/app/common/views/components/messaging-room.message.vue index 70df899f5..ba0ab3209 100644 --- a/src/client/app/common/views/components/messaging-room.message.vue +++ b/src/client/app/common/views/components/messaging-room.message.vue @@ -1,8 +1,6 @@