This commit is contained in:
syuilo 2018-05-27 13:49:09 +09:00
parent 7cdb790f4e
commit d5f92eed8c
69 changed files with 314 additions and 330 deletions

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="index"> <div class="index">
<main v-if="os.isSignedIn"> <main v-if="$store.getters.isSignedIn">
<p class="fetching" v-if="fetching">読み込み中<mk-ellipsis/></p> <p class="fetching" v-if="fetching">読み込み中<mk-ellipsis/></p>
<x-form <x-form
ref="form" ref="form"
@ -22,7 +22,7 @@
<p>セッションが存在しません</p> <p>セッションが存在しません</p>
</div> </div>
</main> </main>
<main class="signin" v-if="!os.isSignedIn"> <main class="signin" v-if="!$store.getters.isSignedIn">
<h1>サインインしてください</h1> <h1>サインインしてください</h1>
<mk-signin/> <mk-signin/>
</main> </main>
@ -51,7 +51,7 @@ export default Vue.extend({
} }
}, },
mounted() { mounted() {
if (!this.$root.$data.os.isSignedIn) return; if (!this.$root.$data.$store.getters.isSignedIn) return;
// Fetch session // Fetch session
(this as any).api('auth/session/show', { (this as any).api('auth/session/show', {

View File

@ -24,10 +24,8 @@ export class HomeStream extends Stream {
if (os.debug) { if (os.debug) {
console.log('I updated:', i); console.log('I updated:', i);
} }
merge(me, i);
// キャッシュ更新 os.store.dispatch('mergeMe', i);
os.bakeMe();
}); });
this.on('clientSettingUpdated', x => { this.on('clientSettingUpdated', x => {

View File

@ -32,7 +32,7 @@ export default Vue.extend({
? `rgb(${ this.user.avatarColor.join(',') })` ? `rgb(${ this.user.avatarColor.join(',') })`
: null, : null,
backgroundImage: this.lightmode ? null : `url(${ this.user.avatarUrl }?thumbnail)`, backgroundImage: this.lightmode ? null : `url(${ this.user.avatarUrl }?thumbnail)`,
borderRadius: (this as any).clientSettings.circleIcons ? '100%' : null borderRadius: this.$store.state.settings.circleIcons ? '100%' : null
}; };
} }
} }

View File

@ -8,7 +8,7 @@
<img src="/assets/desktop/messaging/delete.png" alt="Delete"/> <img src="/assets/desktop/messaging/delete.png" alt="Delete"/>
</button> </button>
<div class="content" v-if="!message.isDeleted"> <div class="content" v-if="!message.isDeleted">
<mk-note-html class="text" v-if="message.text" ref="text" :text="message.text" :i="os.i"/> <mk-note-html class="text" v-if="message.text" ref="text" :text="message.text" :i="$store.state.i"/>
<div class="file" v-if="message.file"> <div class="file" v-if="message.file">
<a :href="message.file.url" target="_blank" :title="message.file.name"> <a :href="message.file.url" target="_blank" :title="message.file.name">
<img v-if="message.file.type.split('/')[0] == 'image'" :src="message.file.url" :alt="message.file.name"/> <img v-if="message.file.type.split('/')[0] == 'image'" :src="message.file.url" :alt="message.file.name"/>
@ -42,7 +42,7 @@ export default Vue.extend({
}, },
computed: { computed: {
isMe(): boolean { isMe(): boolean {
return this.message.userId == (this as any).os.i.id; return this.message.userId == this.$store.state.i.id;
}, },
urls(): string[] { urls(): string[] {
if (this.message.text) { if (this.message.text) {

View File

@ -72,7 +72,7 @@ export default Vue.extend({
}, },
mounted() { mounted() {
this.connection = new MessagingStream((this as any).os, (this as any).os.i, this.user.id); this.connection = new MessagingStream((this as any).os, this.$store.state.i, this.user.id);
this.connection.on('message', this.onMessage); this.connection.on('message', this.onMessage);
this.connection.on('read', this.onRead); this.connection.on('read', this.onRead);
@ -164,7 +164,7 @@ export default Vue.extend({
const isBottom = this.isBottom(); const isBottom = this.isBottom();
this.messages.push(message); this.messages.push(message);
if (message.userId != (this as any).os.i.id && !document.hidden) { if (message.userId != this.$store.state.i.id && !document.hidden) {
this.connection.send({ this.connection.send({
type: 'read', type: 'read',
id: message.id id: message.id
@ -176,7 +176,7 @@ export default Vue.extend({
this.$nextTick(() => { this.$nextTick(() => {
this.scrollToBottom(); this.scrollToBottom();
}); });
} else if (message.userId != (this as any).os.i.id) { } else if (message.userId != this.$store.state.i.id) {
// Notify // Notify
this.notifyNewMessage(); this.notifyNewMessage();
} }
@ -229,7 +229,7 @@ export default Vue.extend({
onVisibilitychange() { onVisibilitychange() {
if (document.hidden) return; if (document.hidden) return;
this.messages.forEach(message => { this.messages.forEach(message => {
if (message.userId !== (this as any).os.i.id && !message.isRead) { if (message.userId !== this.$store.state.i.id && !message.isRead) {
this.connection.send({ this.connection.send({
type: 'read', type: 'read',
id: message.id id: message.id

View File

@ -95,7 +95,7 @@ export default Vue.extend({
methods: { methods: {
getAcct, getAcct,
isMe(message) { isMe(message) {
return message.userId == (this as any).os.i.id; return message.userId == this.$store.state.i.id;
}, },
onMessage(message) { onMessage(message) {
this.messages = this.messages.filter(m => !( this.messages = this.messages.filter(m => !(

View File

@ -3,7 +3,7 @@
<div class="backdrop" ref="backdrop" @click="close"></div> <div class="backdrop" ref="backdrop" @click="close"></div>
<div class="popover" :class="{ compact }" ref="popover"> <div class="popover" :class="{ compact }" ref="popover">
<button @click="favorite">%i18n:@favorite%</button> <button @click="favorite">%i18n:@favorite%</button>
<button v-if="note.userId == os.i.id" @click="pin">%i18n:@pin%</button> <button v-if="note.userId == $store.state.i.id" @click="pin">%i18n:@pin%</button>
<a v-if="note.uri" :href="note.uri" target="_blank">%i18n:@remote%</a> <a v-if="note.uri" :href="note.uri" target="_blank">%i18n:@remote%</a>
</div> </div>
</div> </div>

View File

@ -61,13 +61,13 @@ export default Vue.extend({
computed: { computed: {
iAmPlayer(): boolean { iAmPlayer(): boolean {
if (!(this as any).os.isSignedIn) return false; if (!this.$store.getters.isSignedIn) return false;
return this.game.user1Id == (this as any).os.i.id || this.game.user2Id == (this as any).os.i.id; return this.game.user1Id == this.$store.state.i.id || this.game.user2Id == this.$store.state.i.id;
}, },
myColor(): Color { myColor(): Color {
if (!this.iAmPlayer) return null; if (!this.iAmPlayer) return null;
if (this.game.user1Id == (this as any).os.i.id && this.game.black == 1) return true; if (this.game.user1Id == this.$store.state.i.id && this.game.black == 1) return true;
if (this.game.user2Id == (this as any).os.i.id && this.game.black == 2) return true; if (this.game.user2Id == this.$store.state.i.id && this.game.black == 2) return true;
return false; return false;
}, },
opColor(): Color { opColor(): Color {
@ -91,7 +91,7 @@ export default Vue.extend({
}, },
isMyTurn(): boolean { isMyTurn(): boolean {
if (this.turnUser == null) return null; if (this.turnUser == null) return null;
return this.turnUser.id == (this as any).os.i.id; return this.turnUser.id == this.$store.state.i.id;
} }
}, },

View File

@ -25,7 +25,7 @@ export default Vue.extend({
}, },
created() { created() {
this.g = this.game; this.g = this.game;
this.connection = new OthelloGameStream((this as any).os, (this as any).os.i, this.game); this.connection = new OthelloGameStream((this as any).os, this.$store.state.i, this.game);
this.connection.on('started', this.onStarted); this.connection.on('started', this.onStarted);
}, },
beforeDestroy() { beforeDestroy() {

View File

@ -116,13 +116,13 @@ export default Vue.extend({
return categories.filter((item, pos) => categories.indexOf(item) == pos); return categories.filter((item, pos) => categories.indexOf(item) == pos);
}, },
isAccepted(): boolean { isAccepted(): boolean {
if (this.game.user1Id == (this as any).os.i.id && this.game.user1Accepted) return true; if (this.game.user1Id == this.$store.state.i.id && this.game.user1Accepted) return true;
if (this.game.user2Id == (this as any).os.i.id && this.game.user2Accepted) return true; if (this.game.user2Id == this.$store.state.i.id && this.game.user2Accepted) return true;
return false; return false;
}, },
isOpAccepted(): boolean { isOpAccepted(): boolean {
if (this.game.user1Id != (this as any).os.i.id && this.game.user1Accepted) return true; if (this.game.user1Id != this.$store.state.i.id && this.game.user1Accepted) return true;
if (this.game.user2Id != (this as any).os.i.id && this.game.user2Accepted) return true; if (this.game.user2Id != this.$store.state.i.id && this.game.user2Accepted) return true;
return false; return false;
} }
}, },
@ -133,8 +133,8 @@ export default Vue.extend({
this.connection.on('init-form', this.onInitForm); this.connection.on('init-form', this.onInitForm);
this.connection.on('message', this.onMessage); this.connection.on('message', this.onMessage);
if (this.game.user1Id != (this as any).os.i.id && this.game.settings.form1) this.form = this.game.settings.form1; if (this.game.user1Id != this.$store.state.i.id && this.game.settings.form1) this.form = this.game.settings.form1;
if (this.game.user2Id != (this as any).os.i.id && this.game.settings.form2) this.form = this.game.settings.form2; if (this.game.user2Id != this.$store.state.i.id && this.game.settings.form2) this.form = this.game.settings.form2;
}, },
beforeDestroy() { beforeDestroy() {
@ -185,12 +185,12 @@ export default Vue.extend({
}, },
onInitForm(x) { onInitForm(x) {
if (x.userId == (this as any).os.i.id) return; if (x.userId == this.$store.state.i.id) return;
this.form = x.form; this.form = x.form;
}, },
onMessage(x) { onMessage(x) {
if (x.userId == (this as any).os.i.id) return; if (x.userId == this.$store.state.i.id) return;
this.messages.unshift(x.message); this.messages.unshift(x.message);
}, },

View File

@ -1,13 +1,13 @@
<template> <template>
<div class="mk-twitter-setting"> <div class="mk-twitter-setting">
<p>%i18n:@description%<a :href="`${docsUrl}/link-to-twitter`" target="_blank">%i18n:@detail%</a></p> <p>%i18n:@description%<a :href="`${docsUrl}/link-to-twitter`" target="_blank">%i18n:@detail%</a></p>
<p class="account" v-if="os.i.twitter" :title="`Twitter ID: ${os.i.twitter.userId}`">%i18n:@connected-to%: <a :href="`https://twitter.com/${os.i.twitter.screenName}`" target="_blank">@{{ os.i.twitter.screenName }}</a></p> <p class="account" v-if="$store.state.i.twitter" :title="`Twitter ID: ${$store.state.i.twitter.userId}`">%i18n:@connected-to%: <a :href="`https://twitter.com/${$store.state.i.twitter.screenName}`" target="_blank">@{{ $store.state.i.twitter.screenName }}</a></p>
<p> <p>
<a :href="`${apiUrl}/connect/twitter`" target="_blank" @click.prevent="connect">{{ os.i.twitter ? '%i18n:@reconnect%' : '%i18n:@connect%' }}</a> <a :href="`${apiUrl}/connect/twitter`" target="_blank" @click.prevent="connect">{{ $store.state.i.twitter ? '%i18n:@reconnect%' : '%i18n:@connect%' }}</a>
<span v-if="os.i.twitter"> or </span> <span v-if="$store.state.i.twitter"> or </span>
<a :href="`${apiUrl}/disconnect/twitter`" target="_blank" v-if="os.i.twitter" @click.prevent="disconnect">%i18n:@disconnect%</a> <a :href="`${apiUrl}/disconnect/twitter`" target="_blank" v-if="$store.state.i.twitter" @click.prevent="disconnect">%i18n:@disconnect%</a>
</p> </p>
<p class="id" v-if="os.i.twitter">Twitter ID: {{ os.i.twitter.userId }}</p> <p class="id" v-if="$store.state.i.twitter">Twitter ID: {{ $store.state.i.twitter.userId }}</p>
</div> </div>
</template> </template>
@ -24,8 +24,8 @@ export default Vue.extend({
}; };
}, },
mounted() { mounted() {
this.$watch('os.i', () => { this.$watch('$store.state.i', () => {
if ((this as any).os.i.twitter) { if (this.$store.state.i.twitter) {
if (this.form) this.form.close(); if (this.form) this.form.close();
} }
}, { }, {

View File

@ -50,7 +50,7 @@ export default Vue.extend({
reader.readAsDataURL(file); reader.readAsDataURL(file);
const data = new FormData(); const data = new FormData();
data.append('i', (this as any).os.i.token); data.append('i', this.$store.state.i.token);
data.append('file', file); data.append('file', file);
if (folder) data.append('folderId', folder); if (folder) data.append('folderId', folder);

View File

@ -1,18 +1,17 @@
import OS from '../../mios';
import { url } from '../../config'; import { url } from '../../config';
import MkChooseFileFromDriveWindow from '../views/components/choose-file-from-drive-window.vue'; import MkChooseFileFromDriveWindow from '../views/components/choose-file-from-drive-window.vue';
export default function(opts) { export default (os: OS) => opts => {
return new Promise((res, rej) => { return new Promise((res, rej) => {
const o = opts || {}; const o = opts || {};
if (document.body.clientWidth > 800) { if (document.body.clientWidth > 800) {
const w = new MkChooseFileFromDriveWindow({ const w = os.new(MkChooseFileFromDriveWindow, {
propsData: { title: o.title,
title: o.title, multiple: o.multiple,
multiple: o.multiple, initFolder: o.currentFolder
initFolder: o.currentFolder });
}
}).$mount();
w.$once('selected', file => { w.$once('selected', file => {
res(file); res(file);
}); });
@ -27,4 +26,4 @@ export default function(opts) {
'height=500, width=800'); 'height=500, width=800');
} }
}); });
} };

View File

@ -1,17 +1,16 @@
import OS from '../../mios';
import MkChooseFolderFromDriveWindow from '../views/components/choose-folder-from-drive-window.vue'; import MkChooseFolderFromDriveWindow from '../views/components/choose-folder-from-drive-window.vue';
export default function(opts) { export default (os: OS) => opts => {
return new Promise((res, rej) => { return new Promise((res, rej) => {
const o = opts || {}; const o = opts || {};
const w = new MkChooseFolderFromDriveWindow({ const w = os.new(MkChooseFolderFromDriveWindow, {
propsData: { title: o.title,
title: o.title, initFolder: o.currentFolder
initFolder: o.currentFolder });
}
}).$mount();
w.$once('selected', folder => { w.$once('selected', folder => {
res(folder); res(folder);
}); });
document.body.appendChild(w.$el); document.body.appendChild(w.$el);
}); });
} };

View File

@ -6,17 +6,15 @@ import ProgressDialog from '../views/components/progress-dialog.vue';
export default (os: OS) => (cb, file = null) => { export default (os: OS) => (cb, file = null) => {
const fileSelected = file => { const fileSelected = file => {
const w = new CropWindow({ const w = os.new(CropWindow, {
propsData: { image: file,
image: file, title: 'アバターとして表示する部分を選択',
title: 'アバターとして表示する部分を選択', aspectRatio: 1 / 1
aspectRatio: 1 / 1 });
}
}).$mount();
w.$once('cropped', blob => { w.$once('cropped', blob => {
const data = new FormData(); const data = new FormData();
data.append('i', os.i.token); data.append('i', os.store.state.i.token);
data.append('file', blob, file.name + '.cropped.png'); data.append('file', blob, file.name + '.cropped.png');
os.api('drive/folders/find', { os.api('drive/folders/find', {
@ -42,11 +40,9 @@ export default (os: OS) => (cb, file = null) => {
}; };
const upload = (data, folder) => { const upload = (data, folder) => {
const dialog = new ProgressDialog({ const dialog = os.new(ProgressDialog, {
propsData: { title: '新しいアバターをアップロードしています'
title: '新しいアバターをアップロードしています' });
}
}).$mount();
document.body.appendChild(dialog.$el); document.body.appendChild(dialog.$el);
if (folder) data.append('folderId', folder.id); if (folder) data.append('folderId', folder.id);
@ -70,8 +66,14 @@ export default (os: OS) => (cb, file = null) => {
os.api('i/update', { os.api('i/update', {
avatarId: file.id avatarId: file.id
}).then(i => { }).then(i => {
os.i.avatarId = i.avatarId; os.store.commit('updateIKeyValue', {
os.i.avatarUrl = i.avatarUrl; key: 'avatarId',
value: i.avatarId
});
os.store.commit('updateIKeyValue', {
key: 'avatarUrl',
value: i.avatarUrl
});
os.apis.dialog({ os.apis.dialog({
title: '%fa:info-circle%アバターを更新しました', title: '%fa:info-circle%アバターを更新しました',

View File

@ -6,17 +6,15 @@ import ProgressDialog from '../views/components/progress-dialog.vue';
export default (os: OS) => { export default (os: OS) => {
const cropImage = file => new Promise((resolve, reject) => { const cropImage = file => new Promise((resolve, reject) => {
const w = new CropWindow({ const w = os.new(CropWindow, {
propsData: { image: file,
image: file, title: 'バナーとして表示する部分を選択',
title: 'バナーとして表示する部分を選択', aspectRatio: 16 / 9
aspectRatio: 16 / 9 });
}
}).$mount();
w.$once('cropped', blob => { w.$once('cropped', blob => {
const data = new FormData(); const data = new FormData();
data.append('i', os.i.token); data.append('i', os.store.state.i.token);
data.append('file', blob, file.name + '.cropped.png'); data.append('file', blob, file.name + '.cropped.png');
os.api('drive/folders/find', { os.api('drive/folders/find', {
@ -44,11 +42,9 @@ export default (os: OS) => {
}); });
const upload = (data, folder) => new Promise((resolve, reject) => { const upload = (data, folder) => new Promise((resolve, reject) => {
const dialog = new ProgressDialog({ const dialog = os.new(ProgressDialog, {
propsData: { title: '新しいバナーをアップロードしています'
title: '新しいバナーをアップロードしています' });
}
}).$mount();
document.body.appendChild(dialog.$el); document.body.appendChild(dialog.$el);
if (folder) data.append('folderId', folder.id); if (folder) data.append('folderId', folder.id);
@ -73,8 +69,14 @@ export default (os: OS) => {
return os.api('i/update', { return os.api('i/update', {
bannerId: file.id bannerId: file.id
}).then(i => { }).then(i => {
os.i.bannerId = i.bannerId; os.store.commit('updateIKeyValue', {
os.i.bannerUrl = i.bannerUrl; key: 'bannerId',
value: i.bannerId
});
os.store.commit('updateIKeyValue', {
key: 'bannerUrl',
value: i.bannerUrl
});
os.apis.dialog({ os.apis.dialog({
title: '%fa:info-circle%バナーを更新しました', title: '%fa:info-circle%バナーを更新しました',

View File

@ -2,7 +2,6 @@
* Desktop Client * Desktop Client
*/ */
import Vue from 'vue';
import VueRouter from 'vue-router'; import VueRouter from 'vue-router';
// Style // Style
@ -68,8 +67,8 @@ init(async (launch) => {
// Launch the app // Launch the app
const [, os] = launch(router, os => ({ const [, os] = launch(router, os => ({
chooseDriveFolder, chooseDriveFolder: chooseDriveFolder(os),
chooseDriveFile, chooseDriveFile: chooseDriveFile(os),
dialog, dialog,
input, input,
post, post,

View File

@ -9,10 +9,10 @@
@contextmenu.prevent.stop="onContextmenu" @contextmenu.prevent.stop="onContextmenu"
:title="title" :title="title"
> >
<div class="label" v-if="os.i.avatarId == file.id"><img src="/assets/label.svg"/> <div class="label" v-if="$store.state.i.avatarId == file.id"><img src="/assets/label.svg"/>
<p>%i18n:@avatar%</p> <p>%i18n:@avatar%</p>
</div> </div>
<div class="label" v-if="os.i.bannerId == file.id"><img src="/assets/label.svg"/> <div class="label" v-if="$store.state.i.bannerId == file.id"><img src="/assets/label.svg"/>
<p>%i18n:@banner%</p> <p>%i18n:@banner%</p>
</div> </div>
<div class="thumbnail" ref="thumbnail" :style="`background-color: ${ background }`"> <div class="thumbnail" ref="thumbnail" :style="`background-color: ${ background }`">

View File

@ -51,7 +51,7 @@
<div class="main"> <div class="main">
<a @click="hint">カスタマイズのヒント</a> <a @click="hint">カスタマイズのヒント</a>
<div> <div>
<mk-post-form v-if="clientSettings.showPostFormOnTopOfTl"/> <mk-post-form v-if="$store.state.settings.showPostFormOnTopOfTl"/>
<mk-timeline ref="tl" @loaded="onTlLoaded"/> <mk-timeline ref="tl" @loaded="onTlLoaded"/>
</div> </div>
</div> </div>
@ -61,7 +61,7 @@
<component v-for="widget in widgets[place]" :is="`mkw-${widget.name}`" :key="widget.id" :ref="widget.id" :widget="widget" @chosen="warp"/> <component v-for="widget in widgets[place]" :is="`mkw-${widget.name}`" :key="widget.id" :ref="widget.id" :widget="widget" @chosen="warp"/>
</div> </div>
<div class="main"> <div class="main">
<mk-post-form v-if="clientSettings.showPostFormOnTopOfTl"/> <mk-post-form v-if="$store.state.settings.showPostFormOnTopOfTl"/>
<mk-timeline ref="tl" @loaded="onTlLoaded" v-if="mode == 'timeline'"/> <mk-timeline ref="tl" @loaded="onTlLoaded" v-if="mode == 'timeline'"/>
<mk-mentions @loaded="onTlLoaded" v-if="mode == 'mentions'"/> <mk-mentions @loaded="onTlLoaded" v-if="mode == 'mentions'"/>
</div> </div>

View File

@ -16,7 +16,7 @@
<div class="body"> <div class="body">
<div class="text"> <div class="text">
<span v-if="note.isHidden" style="opacity: 0.5">%i18n:@private%</span> <span v-if="note.isHidden" style="opacity: 0.5">%i18n:@private%</span>
<mk-note-html v-if="note.text" :text="note.text" :i="os.i"/> <mk-note-html v-if="note.text" :text="note.text" :i="$store.state.i"/>
</div> </div>
<div class="media" v-if="note.mediaIds.length > 0"> <div class="media" v-if="note.mediaIds.length > 0">
<mk-media-list :media-list="note.media"/> <mk-media-list :media-list="note.media"/>

View File

@ -39,7 +39,7 @@
<div class="body"> <div class="body">
<div class="text"> <div class="text">
<span v-if="p.isHidden" style="opacity: 0.5">%i18n:@private%</span> <span v-if="p.isHidden" style="opacity: 0.5">%i18n:@private%</span>
<mk-note-html v-if="p.text" :text="p.text" :i="os.i"/> <mk-note-html v-if="p.text" :text="p.text" :i="$store.state.i"/>
</div> </div>
<div class="media" v-if="p.media.length > 0"> <div class="media" v-if="p.media.length > 0">
<mk-media-list :media-list="p.media" :raw="true"/> <mk-media-list :media-list="p.media" :raw="true"/>
@ -158,7 +158,7 @@ export default Vue.extend({
// Draw map // Draw map
if (this.p.geo) { if (this.p.geo) {
const shouldShowMap = (this as any).os.isSignedIn ? (this as any).clientSettings.showMaps : true; const shouldShowMap = this.$store.getters.isSignedIn ? this.$store.state.settings.showMaps : true;
if (shouldShowMap) { if (shouldShowMap) {
(this as any).os.getGoogleMaps().then(maps => { (this as any).os.getGoogleMaps().then(maps => {
const uluru = new maps.LatLng(this.p.geo.coordinates[1], this.p.geo.coordinates[0]); const uluru = new maps.LatLng(this.p.geo.coordinates[1], this.p.geo.coordinates[0]);

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="note" tabindex="-1" :title="title" @keydown="onKeydown"> <div class="note" tabindex="-1" :title="title" @keydown="onKeydown">
<div class="reply-to" v-if="p.reply && (!os.isSignedIn || clientSettings.showReplyTarget)"> <div class="reply-to" v-if="p.reply && (!$store.getters.isSignedIn || $store.state.settings.showReplyTarget)">
<x-sub :note="p.reply"/> <x-sub :note="p.reply"/>
</div> </div>
<div class="renote" v-if="isRenote"> <div class="renote" v-if="isRenote">
@ -43,7 +43,7 @@
<div class="text"> <div class="text">
<span v-if="p.isHidden" style="opacity: 0.5">(この投稿は非公開です)</span> <span v-if="p.isHidden" style="opacity: 0.5">(この投稿は非公開です)</span>
<a class="reply" v-if="p.reply">%fa:reply%</a> <a class="reply" v-if="p.reply">%fa:reply%</a>
<mk-note-html v-if="p.text && !canHideText(p)" :text="p.text" :i="os.i" :class="$style.text"/> <mk-note-html v-if="p.text && !canHideText(p)" :text="p.text" :i="$store.state.i" :class="$style.text"/>
<a class="rp" v-if="p.renote">RP:</a> <a class="rp" v-if="p.renote">RP:</a>
</div> </div>
<div class="media" v-if="p.media.length > 0"> <div class="media" v-if="p.media.length > 0">
@ -166,7 +166,7 @@ export default Vue.extend({
}, },
created() { created() {
if ((this as any).os.isSignedIn) { if (this.$store.getters.isSignedIn) {
this.connection = (this as any).os.stream.getConnection(); this.connection = (this as any).os.stream.getConnection();
this.connectionId = (this as any).os.stream.use(); this.connectionId = (this as any).os.stream.use();
} }
@ -175,13 +175,13 @@ export default Vue.extend({
mounted() { mounted() {
this.capture(true); this.capture(true);
if ((this as any).os.isSignedIn) { if (this.$store.getters.isSignedIn) {
this.connection.on('_connected_', this.onStreamConnected); this.connection.on('_connected_', this.onStreamConnected);
} }
// Draw map // Draw map
if (this.p.geo) { if (this.p.geo) {
const shouldShowMap = (this as any).os.isSignedIn ? (this as any).clientSettings.showMaps : true; const shouldShowMap = this.$store.getters.isSignedIn ? this.$store.state.settings.showMaps : true;
if (shouldShowMap) { if (shouldShowMap) {
(this as any).os.getGoogleMaps().then(maps => { (this as any).os.getGoogleMaps().then(maps => {
const uluru = new maps.LatLng(this.p.geo.coordinates[1], this.p.geo.coordinates[0]); const uluru = new maps.LatLng(this.p.geo.coordinates[1], this.p.geo.coordinates[0]);
@ -201,7 +201,7 @@ export default Vue.extend({
beforeDestroy() { beforeDestroy() {
this.decapture(true); this.decapture(true);
if ((this as any).os.isSignedIn) { if (this.$store.getters.isSignedIn) {
this.connection.off('_connected_', this.onStreamConnected); this.connection.off('_connected_', this.onStreamConnected);
(this as any).os.stream.dispose(this.connectionId); (this as any).os.stream.dispose(this.connectionId);
} }
@ -211,7 +211,7 @@ export default Vue.extend({
canHideText, canHideText,
capture(withHandler = false) { capture(withHandler = false) {
if ((this as any).os.isSignedIn) { if (this.$store.getters.isSignedIn) {
this.connection.send({ this.connection.send({
type: 'capture', type: 'capture',
id: this.p.id id: this.p.id
@ -221,7 +221,7 @@ export default Vue.extend({
}, },
decapture(withHandler = false) { decapture(withHandler = false) {
if ((this as any).os.isSignedIn) { if (this.$store.getters.isSignedIn) {
this.connection.send({ this.connection.send({
type: 'decapture', type: 'decapture',
id: this.p.id id: this.p.id

View File

@ -118,24 +118,24 @@ export default Vue.extend({
prepend(note, silent = false) { prepend(note, silent = false) {
//#region //#region
const isMyNote = note.userId == (this as any).os.i.id; const isMyNote = note.userId == this.$store.state.i.id;
const isPureRenote = note.renoteId != null && note.text == null && note.mediaIds.length == 0 && note.poll == null; const isPureRenote = note.renoteId != null && note.text == null && note.mediaIds.length == 0 && note.poll == null;
if ((this as any).clientSettings.showMyRenotes === false) { if (this.$store.state.settings.showMyRenotes === false) {
if (isMyNote && isPureRenote) { if (isMyNote && isPureRenote) {
return; return;
} }
} }
if ((this as any).clientSettings.showRenotedMyNotes === false) { if (this.$store.state.settings.showRenotedMyNotes === false) {
if (isPureRenote && (note.renote.userId == (this as any).os.i.id)) { if (isPureRenote && (note.renote.userId == this.$store.state.i.id)) {
return; return;
} }
} }
//#endregion //#endregion
// 稿 // 稿
if ((document.hidden || !this.isScrollTop()) && note.userId !== (this as any).os.i.id) { if ((document.hidden || !this.isScrollTop()) && note.userId !== this.$store.state.i.id) {
this.unreadCount++; this.unreadCount++;
document.title = `(${this.unreadCount}) ${getNoteSummary(note)}`; document.title = `(${this.unreadCount}) ${getNoteSummary(note)}`;
} }
@ -199,7 +199,7 @@ export default Vue.extend({
this.clearNotification(); this.clearNotification();
} }
if ((this as any).clientSettings.fetchOnScroll !== false) { if (this.$store.state.settings.fetchOnScroll !== false) {
const current = window.scrollY + window.innerHeight; const current = window.scrollY + window.innerHeight;
if (current > document.body.offsetHeight - 8) this.loadMore(); if (current > document.body.offsetHeight - 8) this.loadMore();
} }

View File

@ -118,7 +118,7 @@ export default Vue.extend({
const mention = x.host ? `@${x.username}@${x.host}` : `@${x.username}`; const mention = x.host ? `@${x.username}@${x.host}` : `@${x.username}`;
// //
if (this.os.i.username == x.username && x.host == null) return; if (this.$store.state.i.username == x.username && x.host == null) return;
// //
if (this.text.indexOf(`${mention} `) != -1) return; if (this.text.indexOf(`${mention} `) != -1) return;

View File

@ -2,8 +2,8 @@
<div class="2fa"> <div class="2fa">
<p>%i18n:@intro%<a href="%i18n:@url%" target="_blank">%i18n:@detail%</a></p> <p>%i18n:@intro%<a href="%i18n:@url%" target="_blank">%i18n:@detail%</a></p>
<div class="ui info warn"><p>%fa:exclamation-triangle%%i18n:@caution%</p></div> <div class="ui info warn"><p>%fa:exclamation-triangle%%i18n:@caution%</p></div>
<p v-if="!data && !os.i.twoFactorEnabled"><button @click="register" class="ui primary">%i18n:@register%</button></p> <p v-if="!data && !$store.state.i.twoFactorEnabled"><button @click="register" class="ui primary">%i18n:@register%</button></p>
<template v-if="os.i.twoFactorEnabled"> <template v-if="$store.state.i.twoFactorEnabled">
<p>%i18n:@already-registered%</p> <p>%i18n:@already-registered%</p>
<button @click="unregister" class="ui">%i18n:@unregister%</button> <button @click="unregister" class="ui">%i18n:@unregister%</button>
</template> </template>
@ -54,7 +54,7 @@ export default Vue.extend({
password: password password: password
}).then(() => { }).then(() => {
(this as any).apis.notify('%i18n:@unregistered%'); (this as any).apis.notify('%i18n:@unregistered%');
(this as any).os.i.twoFactorEnabled = false; this.$store.state.i.twoFactorEnabled = false;
}); });
}); });
}, },
@ -64,7 +64,7 @@ export default Vue.extend({
token: this.token token: this.token
}).then(() => { }).then(() => {
(this as any).apis.notify('%i18n:@success%'); (this as any).apis.notify('%i18n:@success%');
(this as any).os.i.twoFactorEnabled = true; this.$store.state.i.twoFactorEnabled = true;
}).catch(() => { }).catch(() => {
(this as any).apis.notify('%i18n:@failed%'); (this as any).apis.notify('%i18n:@failed%');
}); });

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="root api"> <div class="root api">
<p>%i18n:@token% <code>{{ os.i.token }}</code></p> <p>%i18n:@token% <code>{{ $store.state.i.token }}</code></p>
<p>%i18n:@intro%</p> <p>%i18n:@intro%</p>
<div class="ui info warn"><p>%fa:exclamation-triangle%%i18n:@caution%</p></div> <div class="ui info warn"><p>%fa:exclamation-triangle%%i18n:@caution%</p></div>
<p>%i18n:@regeneration-of-token%</p> <p>%i18n:@regeneration-of-token%</p>

View File

@ -2,7 +2,7 @@
<div class="profile"> <div class="profile">
<label class="avatar ui from group"> <label class="avatar ui from group">
<p>%i18n:@avatar%</p> <p>%i18n:@avatar%</p>
<img class="avatar" :src="`${os.i.avatarUrl}?thumbnail&size=64`" alt="avatar"/> <img class="avatar" :src="`${$store.state.i.avatarUrl}?thumbnail&size=64`" alt="avatar"/>
<button class="ui" @click="updateAvatar">%i18n:@choice-avatar%</button> <button class="ui" @click="updateAvatar">%i18n:@choice-avatar%</button>
</label> </label>
<label class="ui from group"> <label class="ui from group">
@ -24,8 +24,8 @@
<button class="ui primary" @click="save">%i18n:@save%</button> <button class="ui primary" @click="save">%i18n:@save%</button>
<section> <section>
<h2>その他</h2> <h2>その他</h2>
<mk-switch v-model="os.i.isBot" @change="onChangeIsBot" text="%i18n:@is-bot%"/> <mk-switch v-model="$store.state.i.isBot" @change="onChangeIsBot" text="%i18n:@is-bot%"/>
<mk-switch v-model="os.i.isCat" @change="onChangeIsCat" text="%i18n:@is-cat%"/> <mk-switch v-model="$store.state.i.isCat" @change="onChangeIsCat" text="%i18n:@is-cat%"/>
</section> </section>
</div> </div>
</template> </template>
@ -43,10 +43,10 @@ export default Vue.extend({
}; };
}, },
created() { created() {
this.name = (this as any).os.i.name || ''; this.name = this.$store.state.i.name || '';
this.location = (this as any).os.i.profile.location; this.location = this.$store.state.i.profile.location;
this.description = (this as any).os.i.description; this.description = this.$store.state.i.description;
this.birthday = (this as any).os.i.profile.birthday; this.birthday = this.$store.state.i.profile.birthday;
}, },
methods: { methods: {
updateAvatar() { updateAvatar() {
@ -64,12 +64,12 @@ export default Vue.extend({
}, },
onChangeIsBot() { onChangeIsBot() {
(this as any).api('i/update', { (this as any).api('i/update', {
isBot: (this as any).os.i.isBot isBot: this.$store.state.i.isBot
}); });
}, },
onChangeIsCat() { onChangeIsCat() {
(this as any).api('i/update', { (this as any).api('i/update', {
isCat: (this as any).os.i.isCat isCat: this.$store.state.i.isCat
}); });
} }
} }

View File

@ -20,7 +20,7 @@
<section class="web" v-show="page == 'web'"> <section class="web" v-show="page == 'web'">
<h1>%i18n:@behaviour%</h1> <h1>%i18n:@behaviour%</h1>
<mk-switch v-model="clientSettings.fetchOnScroll" @change="onChangeFetchOnScroll" text="%i18n:@fetch-on-scroll%"> <mk-switch v-model="$store.state.settings.fetchOnScroll" @change="onChangeFetchOnScroll" text="%i18n:@fetch-on-scroll%">
<span>%i18n:@fetch-on-scroll-desc%</span> <span>%i18n:@fetch-on-scroll-desc%</span>
</mk-switch> </mk-switch>
<mk-switch v-model="autoPopout" text="%i18n:@auto-popout%"> <mk-switch v-model="autoPopout" text="%i18n:@auto-popout%">
@ -41,14 +41,14 @@
</div> </div>
<div class="div"> <div class="div">
<mk-switch v-model="darkmode" text="%i18n:@dark-mode%"/> <mk-switch v-model="darkmode" text="%i18n:@dark-mode%"/>
<mk-switch v-model="clientSettings.circleIcons" @change="onChangeCircleIcons" text="%i18n:@circle-icons%"/> <mk-switch v-model="$store.state.settings.circleIcons" @change="onChangeCircleIcons" text="%i18n:@circle-icons%"/>
<mk-switch v-model="clientSettings.gradientWindowHeader" @change="onChangeGradientWindowHeader" text="%i18n:@gradient-window-header%"/> <mk-switch v-model="$store.state.settings.gradientWindowHeader" @change="onChangeGradientWindowHeader" text="%i18n:@gradient-window-header%"/>
</div> </div>
<mk-switch v-model="clientSettings.showPostFormOnTopOfTl" @change="onChangeShowPostFormOnTopOfTl" text="%i18n:@post-form-on-timeline%"/> <mk-switch v-model="$store.state.settings.showPostFormOnTopOfTl" @change="onChangeShowPostFormOnTopOfTl" text="%i18n:@post-form-on-timeline%"/>
<mk-switch v-model="clientSettings.showReplyTarget" @change="onChangeShowReplyTarget" text="%i18n:@show-reply-target%"/> <mk-switch v-model="$store.state.settings.showReplyTarget" @change="onChangeShowReplyTarget" text="%i18n:@show-reply-target%"/>
<mk-switch v-model="clientSettings.showMyRenotes" @change="onChangeShowMyRenotes" text="%i18n:@show-my-renotes%"/> <mk-switch v-model="$store.state.settings.showMyRenotes" @change="onChangeShowMyRenotes" text="%i18n:@show-my-renotes%"/>
<mk-switch v-model="clientSettings.showRenotedMyNotes" @change="onChangeShowRenotedMyNotes" text="%i18n:@show-renoted-my-notes%"/> <mk-switch v-model="$store.state.settings.showRenotedMyNotes" @change="onChangeShowRenotedMyNotes" text="%i18n:@show-renoted-my-notes%"/>
<mk-switch v-model="clientSettings.showMaps" @change="onChangeShowMaps" text="%i18n:@show-maps%"> <mk-switch v-model="$store.state.settings.showMaps" @change="onChangeShowMaps" text="%i18n:@show-maps%">
<span>%i18n:@show-maps-desc%</span> <span>%i18n:@show-maps-desc%</span>
</mk-switch> </mk-switch>
</section> </section>
@ -72,7 +72,7 @@
<section class="web" v-show="page == 'web'"> <section class="web" v-show="page == 'web'">
<h1>%i18n:@mobile%</h1> <h1>%i18n:@mobile%</h1>
<mk-switch v-model="clientSettings.disableViaMobile" @change="onChangeDisableViaMobile" text="%i18n:@disable-via-mobile%"/> <mk-switch v-model="$store.state.settings.disableViaMobile" @change="onChangeDisableViaMobile" text="%i18n:@disable-via-mobile%"/>
</section> </section>
<section class="web" v-show="page == 'web'"> <section class="web" v-show="page == 'web'">
@ -100,7 +100,7 @@
<section class="notification" v-show="page == 'notification'"> <section class="notification" v-show="page == 'notification'">
<h1>%i18n:@notification%</h1> <h1>%i18n:@notification%</h1>
<mk-switch v-model="os.i.settings.autoWatch" @change="onChangeAutoWatch" text="%i18n:@auto-watch%"> <mk-switch v-model="$store.state.i.settings.autoWatch" @change="onChangeAutoWatch" text="%i18n:@auto-watch%">
<span>%i18n:@auto-watch-desc%</span> <span>%i18n:@auto-watch-desc%</span>
</mk-switch> </mk-switch>
</section> </section>

View File

@ -3,7 +3,7 @@
<div class="body"> <div class="body">
<span v-if="note.isHidden" style="opacity: 0.5">%i18n:@hidden%</span> <span v-if="note.isHidden" style="opacity: 0.5">%i18n:@hidden%</span>
<a class="reply" v-if="note.replyId">%fa:reply%</a> <a class="reply" v-if="note.replyId">%fa:reply%</a>
<mk-note-html :text="note.text" :i="os.i"/> <mk-note-html :text="note.text" :i="$store.state.i"/>
<a class="rp" v-if="note.renoteId" :href="`/note:${note.renoteId}`">RP: ...</a> <a class="rp" v-if="note.renoteId" :href="`/note:${note.renoteId}`">RP: ...</a>
</div> </div>
<details v-if="note.media.length > 0"> <details v-if="note.media.length > 0">

View File

@ -40,7 +40,7 @@ export default Vue.extend({
computed: { computed: {
alone(): boolean { alone(): boolean {
return (this as any).os.i.followingCount == 0; return this.$store.state.i.followingCount == 0;
}, },
stream(): any { stream(): any {
@ -98,8 +98,8 @@ export default Vue.extend({
(this as any).api(this.endpoint, { (this as any).api(this.endpoint, {
limit: fetchLimit + 1, limit: fetchLimit + 1,
untilDate: this.date ? this.date.getTime() : undefined, untilDate: this.date ? this.date.getTime() : undefined,
includeMyRenotes: (this as any).clientSettings.showMyRenotes, includeMyRenotes: this.$store.state.settings.showMyRenotes,
includeRenotedMyNotes: (this as any).clientSettings.showRenotedMyNotes includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes
}).then(notes => { }).then(notes => {
if (notes.length == fetchLimit + 1) { if (notes.length == fetchLimit + 1) {
notes.pop(); notes.pop();
@ -120,8 +120,8 @@ export default Vue.extend({
const promise = (this as any).api(this.endpoint, { const promise = (this as any).api(this.endpoint, {
limit: fetchLimit + 1, limit: fetchLimit + 1,
untilId: (this.$refs.timeline as any).tail().id, untilId: (this.$refs.timeline as any).tail().id,
includeMyRenotes: (this as any).clientSettings.showMyRenotes, includeMyRenotes: this.$store.state.settings.showMyRenotes,
includeRenotedMyNotes: (this as any).clientSettings.showRenotedMyNotes includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes
}); });
promise.then(notes => { promise.then(notes => {

View File

@ -47,7 +47,7 @@ export default Vue.extend({
if (this.src == 'list') { if (this.src == 'list') {
this.list = this.$store.state.device.tl.arg; this.list = this.$store.state.device.tl.arg;
} }
} else if ((this as any).os.i.followingCount == 0) { } else if (this.$store.state.i.followingCount == 0) {
this.src = 'local'; this.src = 'local';
} }
}, },

View File

@ -1,14 +1,14 @@
<template> <template>
<div class="account"> <div class="account">
<button class="header" :data-active="isOpen" @click="toggle"> <button class="header" :data-active="isOpen" @click="toggle">
<span class="username">{{ os.i.username }}<template v-if="!isOpen">%fa:angle-down%</template><template v-if="isOpen">%fa:angle-up%</template></span> <span class="username">{{ $store.state.i.username }}<template v-if="!isOpen">%fa:angle-down%</template><template v-if="isOpen">%fa:angle-up%</template></span>
<mk-avatar class="avatar" :user="os.i"/> <mk-avatar class="avatar" :user="$store.state.i"/>
</button> </button>
<transition name="zoom-in-top"> <transition name="zoom-in-top">
<div class="menu" v-if="isOpen"> <div class="menu" v-if="isOpen">
<ul> <ul>
<li> <li>
<router-link :to="`/@${ os.i.username }`">%fa:user%<span>%i18n:@profile%</span>%fa:angle-right%</router-link> <router-link :to="`/@${ $store.state.i.username }`">%fa:user%<span>%i18n:@profile%</span>%fa:angle-right%</router-link>
</li> </li>
<li @click="drive"> <li @click="drive">
<p>%fa:cloud%<span>%i18n:@drive%</span>%fa:angle-right%</p> <p>%fa:cloud%<span>%i18n:@drive%</span>%fa:angle-right%</p>

View File

@ -1,7 +1,7 @@
<template> <template>
<div class="nav"> <div class="nav">
<ul> <ul>
<template v-if="os.isSignedIn"> <template v-if="$store.getters.isSignedIn">
<li class="home" :class="{ active: $route.name == 'index' }"> <li class="home" :class="{ active: $route.name == 'index' }">
<router-link to="/"> <router-link to="/">
%fa:home% %fa:home%
@ -42,7 +42,7 @@ export default Vue.extend({
}; };
}, },
mounted() { mounted() {
if ((this as any).os.isSignedIn) { if (this.$store.getters.isSignedIn) {
this.connection = (this as any).os.stream.getConnection(); this.connection = (this as any).os.stream.getConnection();
this.connectionId = (this as any).os.stream.use(); this.connectionId = (this as any).os.stream.use();
@ -60,7 +60,7 @@ export default Vue.extend({
} }
}, },
beforeDestroy() { beforeDestroy() {
if ((this as any).os.isSignedIn) { if (this.$store.getters.isSignedIn) {
this.connection.off('read_all_messaging_messages', this.onReadAllMessagingMessages); this.connection.off('read_all_messaging_messages', this.onReadAllMessagingMessages);
this.connection.off('unread_messaging_message', this.onUnreadMessagingMessage); this.connection.off('unread_messaging_message', this.onUnreadMessagingMessage);
this.connection.off('othello_invited', this.onOthelloInvited); this.connection.off('othello_invited', this.onOthelloInvited);

View File

@ -23,7 +23,7 @@ export default Vue.extend({
}; };
}, },
mounted() { mounted() {
if ((this as any).os.isSignedIn) { if (this.$store.getters.isSignedIn) {
this.connection = (this as any).os.stream.getConnection(); this.connection = (this as any).os.stream.getConnection();
this.connectionId = (this as any).os.stream.use(); this.connectionId = (this as any).os.stream.use();
@ -39,7 +39,7 @@ export default Vue.extend({
} }
}, },
beforeDestroy() { beforeDestroy() {
if ((this as any).os.isSignedIn) { if (this.$store.getters.isSignedIn) {
this.connection.off('read_all_notifications', this.onReadAllNotifications); this.connection.off('read_all_notifications', this.onReadAllNotifications);
this.connection.off('unread_notification', this.onUnreadNotification); this.connection.off('unread_notification', this.onUnreadNotification);
(this as any).os.stream.dispose(this.connectionId); (this as any).os.stream.dispose(this.connectionId);

View File

@ -4,16 +4,16 @@
<div class="main" ref="main"> <div class="main" ref="main">
<div class="backdrop"></div> <div class="backdrop"></div>
<div class="main"> <div class="main">
<p ref="welcomeback" v-if="os.isSignedIn">おかえりなさい<b>{{ os.i | userName }}</b>さん</p> <p ref="welcomeback" v-if="$store.getters.isSignedIn">おかえりなさい<b>{{ $store.state.i | userName }}</b>さん</p>
<div class="container" ref="mainContainer"> <div class="container" ref="mainContainer">
<div class="left"> <div class="left">
<x-nav/> <x-nav/>
</div> </div>
<div class="right"> <div class="right">
<x-search/> <x-search/>
<x-account v-if="os.isSignedIn"/> <x-account v-if="$store.getters.isSignedIn"/>
<x-notifications v-if="os.isSignedIn"/> <x-notifications v-if="$store.getters.isSignedIn"/>
<x-post v-if="os.isSignedIn"/> <x-post v-if="$store.getters.isSignedIn"/>
<x-clock/> <x-clock/>
</div> </div>
</div> </div>
@ -45,11 +45,11 @@ export default Vue.extend({
mounted() { mounted() {
this.$store.commit('setUiHeaderHeight', 48); this.$store.commit('setUiHeaderHeight', 48);
if ((this as any).os.isSignedIn) { if (this.$store.getters.isSignedIn) {
const ago = (new Date().getTime() - new Date((this as any).os.i.lastUsedAt).getTime()) / 1000; const ago = (new Date().getTime() - new Date(this.$store.state.i.lastUsedAt).getTime()) / 1000;
const isHisasiburi = ago >= 3600; const isHisasiburi = ago >= 3600;
(this as any).os.i.lastUsedAt = new Date(); this.$store.state.i.lastUsedAt = new Date();
(this as any).os.bakeMe();
if (isHisasiburi) { if (isHisasiburi) {
(this.$refs.welcomeback as any).style.display = 'block'; (this.$refs.welcomeback as any).style.display = 'block';
(this.$refs.main as any).style.overflow = 'hidden'; (this.$refs.main as any).style.overflow = 'hidden';

View File

@ -4,7 +4,7 @@
<div class="content"> <div class="content">
<slot></slot> <slot></slot>
</div> </div>
<mk-stream-indicator v-if="os.isSignedIn"/> <mk-stream-indicator v-if="$store.getters.isSignedIn"/>
</div> </div>
</template> </template>

View File

@ -32,7 +32,7 @@ export default Vue.extend({
methods: { methods: {
init() { init() {
if (this.connection) this.connection.close(); if (this.connection) this.connection.close();
this.connection = new UserListStream((this as any).os, (this as any).os.i, this.list.id); this.connection = new UserListStream((this as any).os, this.$store.state.i, this.list.id);
this.connection.on('note', this.onNote); this.connection.on('note', this.onNote);
this.connection.on('userAdded', this.onUserAdded); this.connection.on('userAdded', this.onUserAdded);
this.connection.on('userRemoved', this.onUserRemoved); this.connection.on('userRemoved', this.onUserRemoved);
@ -46,8 +46,8 @@ export default Vue.extend({
(this as any).api('notes/user-list-timeline', { (this as any).api('notes/user-list-timeline', {
listId: this.list.id, listId: this.list.id,
limit: fetchLimit + 1, limit: fetchLimit + 1,
includeMyRenotes: (this as any).clientSettings.showMyRenotes, includeMyRenotes: this.$store.state.settings.showMyRenotes,
includeRenotedMyNotes: (this as any).clientSettings.showRenotedMyNotes includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes
}).then(notes => { }).then(notes => {
if (notes.length == fetchLimit + 1) { if (notes.length == fetchLimit + 1) {
notes.pop(); notes.pop();
@ -66,8 +66,8 @@ export default Vue.extend({
listId: this.list.id, listId: this.list.id,
limit: fetchLimit + 1, limit: fetchLimit + 1,
untilId: (this.$refs.timeline as any).tail().id, untilId: (this.$refs.timeline as any).tail().id,
includeMyRenotes: (this as any).clientSettings.showMyRenotes, includeMyRenotes: this.$store.state.settings.showMyRenotes,
includeRenotedMyNotes: (this as any).clientSettings.showRenotedMyNotes includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes
}); });
promise.then(notes => { promise.then(notes => {

View File

@ -19,7 +19,7 @@
<p>%i18n:@followers%</p><a>{{ u.followersCount }}</a> <p>%i18n:@followers%</p><a>{{ u.followersCount }}</a>
</div> </div>
</div> </div>
<mk-follow-button v-if="os.isSignedIn && user.id != os.i.id" :user="u"/> <mk-follow-button v-if="$store.getters.isSignedIn && user.id != $store.state.i.id" :user="u"/>
</template> </template>
</div> </div>
</template> </template>

View File

@ -3,7 +3,7 @@
<nav> <nav>
<div> <div>
<span :data-active="mode == 'all'" @click="mode = 'all'">%i18n:@all%<span>{{ count }}</span></span> <span :data-active="mode == 'all'" @click="mode = 'all'">%i18n:@all%<span>{{ count }}</span></span>
<span v-if="os.isSignedIn && youKnowCount" :data-active="mode == 'iknow'" @click="mode = 'iknow'">%i18n:@iknow%<span>{{ youKnowCount }}</span></span> <span v-if="$store.getters.isSignedIn && youKnowCount" :data-active="mode == 'iknow'" @click="mode = 'iknow'">%i18n:@iknow%<span>{{ youKnowCount }}</span></span>
</div> </div>
</nav> </nav>
<div class="users" v-if="!fetching && users.length != 0"> <div class="users" v-if="!fetching && users.length != 0">

View File

@ -23,9 +23,9 @@ export default Vue.extend({
}, },
computed: { computed: {
withGradient(): boolean { withGradient(): boolean {
return (this as any).os.isSignedIn return this.$store.getters.isSignedIn
? (this as any).clientSettings.gradientWindowHeader != null ? this.$store.state.settings.gradientWindowHeader != null
? (this as any).clientSettings.gradientWindowHeader ? this.$store.state.settings.gradientWindowHeader
: false : false
: false; : false;
} }

View File

@ -4,7 +4,7 @@
<div class="main" ref="main" tabindex="-1" :data-is-modal="isModal" @mousedown="onBodyMousedown" @keydown="onKeydown" :style="{ width, height }"> <div class="main" ref="main" tabindex="-1" :data-is-modal="isModal" @mousedown="onBodyMousedown" @keydown="onKeydown" :style="{ width, height }">
<div class="body"> <div class="body">
<header ref="header" <header ref="header"
:class="{ withGradient: clientSettings.gradientWindowHeader }" :class="{ withGradient: $store.state.settings.gradientWindowHeader }"
@contextmenu.prevent="() => {}" @mousedown.prevent="onHeaderMousedown" @contextmenu.prevent="() => {}" @mousedown.prevent="onHeaderMousedown"
> >
<h1><slot name="header"></slot></h1> <h1><slot name="header"></slot></h1>
@ -95,7 +95,7 @@ export default Vue.extend({
}, },
created() { created() {
if ((this as any).os.store.state.device.autoPopout && this.popoutUrl) { if (this.$store.state.device.autoPopout && this.popoutUrl) {
this.popout(); this.popout();
this.preventMount = true; this.preventMount = true;
} else { } else {

View File

@ -1,5 +1,5 @@
<template> <template>
<component :is="os.isSignedIn ? 'home' : 'welcome'"></component> <component :is="$store.getters.isSignedIn ? 'home' : 'welcome'"></component>
</template> </template>
<script lang="ts"> <script lang="ts">

View File

@ -63,7 +63,7 @@ export default Vue.extend({
}, },
onBannerClick() { onBannerClick() {
if (!(this as any).os.isSignedIn || (this as any).os.i.id != this.user.id) return; if (!this.$store.getters.isSignedIn || this.$store.state.i.id != this.user.id) return;
(this as any).apis.updateBanner().then(i => { (this as any).apis.updateBanner().then(i => {
this.user.bannerUrl = i.bannerUrl; this.user.bannerUrl = i.bannerUrl;

View File

@ -4,7 +4,7 @@
<div ref="left"> <div ref="left">
<x-profile :user="user"/> <x-profile :user="user"/>
<x-photos :user="user"/> <x-photos :user="user"/>
<x-followers-you-know v-if="os.isSignedIn && os.i.id != user.id" :user="user"/> <x-followers-you-know v-if="$store.getters.isSignedIn && $store.state.i.id != user.id" :user="user"/>
<p v-if="user.host === null">%i18n:@last-used-at%: <b><mk-time :time="user.lastUsedAt"/></b></p> <p v-if="user.host === null">%i18n:@last-used-at%: <b><mk-time :time="user.lastUsedAt"/></b></p>
</div> </div>
</div> </div>

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="profile"> <div class="profile">
<div class="friend-form" v-if="os.isSignedIn && os.i.id != user.id"> <div class="friend-form" v-if="$store.getters.isSignedIn && $store.state.i.id != user.id">
<mk-follow-button :user="user" size="big"/> <mk-follow-button :user="user" size="big"/>
<p class="followed" v-if="user.isFollowed">%i18n:@follows-you%</p> <p class="followed" v-if="user.isFollowed">%i18n:@follows-you%</p>
<p class="stalk" v-if="user.isFollowing"> <p class="stalk" v-if="user.isFollowing">

View File

@ -2,7 +2,7 @@
<mk-activity <mk-activity
:design="props.design" :design="props.design"
:init-view="props.view" :init-view="props.view"
:user="os.i" :user="$store.state.i"
@view-changed="viewChanged"/> @view-changed="viewChanged"/>
</template> </template>

View File

@ -4,16 +4,16 @@
:data-melt="props.design == 2" :data-melt="props.design == 2"
> >
<div class="banner" <div class="banner"
:style="os.i.bannerUrl ? `background-image: url(${os.i.bannerUrl}?thumbnail&size=256)` : ''" :style="$store.state.i.bannerUrl ? `background-image: url(${$store.state.i.bannerUrl}?thumbnail&size=256)` : ''"
title="%i18n:@update-banner%" title="%i18n:@update-banner%"
@click="os.apis.updateBanner" @click="os.apis.updateBanner"
></div> ></div>
<mk-avatar class="avatar" :user="os.i" <mk-avatar class="avatar" :user="$store.state.i"
@click="os.apis.updateAvatar" @click="os.apis.updateAvatar"
title="%i18n:@update-avatar%" title="%i18n:@update-avatar%"
/> />
<router-link class="name" :to="os.i | userPage">{{ os.i | userName }}</router-link> <router-link class="name" :to="$store.state.i | userPage">{{ $store.state.i | userName }}</router-link>
<p class="username">@{{ os.i | acct }}</p> <p class="username">@{{ $store.state.i | acct }}</p>
</div> </div>
</template> </template>

View File

@ -143,8 +143,7 @@ export default (callback: (launch: (router: VueRouter, api?: (os: MiOS) => API)
return { return {
os, os,
api: os.api, api: os.api,
apis: os.apis, apis: os.apis
clientSettings: os.store.state.settings
}; };
} }
}); });

View File

@ -1,10 +1,9 @@
import Vue from 'vue'; import Vue from 'vue';
import { EventEmitter } from 'eventemitter3'; import { EventEmitter } from 'eventemitter3';
import * as merge from 'object-assign-deep';
import * as uuid from 'uuid'; import * as uuid from 'uuid';
import initStore from './store'; import initStore from './store';
import { hostname, apiUrl, swPublickey, version, lang, googleMapsApiKey } from './config'; import { apiUrl, swPublickey, version, lang, googleMapsApiKey } from './config';
import Progress from './common/scripts/loading'; import Progress from './common/scripts/loading';
import Connection from './common/scripts/streaming/stream'; import Connection from './common/scripts/streaming/stream';
import { HomeStreamManager } from './common/scripts/streaming/home'; import { HomeStreamManager } from './common/scripts/streaming/home';
@ -82,18 +81,6 @@ export default class MiOS extends EventEmitter {
return w; return w;
} }
/**
* A signing user
*/
public i: { [x: string]: any };
/**
* Whether signed in
*/
public get isSignedIn() {
return this.i != null;
}
/** /**
* Whether is debug mode * Whether is debug mode
*/ */
@ -218,15 +205,8 @@ export default class MiOS extends EventEmitter {
console.error.apply(null, args); console.error.apply(null, args);
} }
public bakeMe() {
// ローカルストレージにキャッシュ
localStorage.setItem('me', JSON.stringify(this.i));
}
public signout() { public signout() {
localStorage.removeItem('me'); this.store.dispatch('logout');
localStorage.removeItem('settings');
document.cookie = `i=; domain=${hostname}; expires=Thu, 01 Jan 1970 00:00:01 GMT;`;
location.href = '/'; location.href = '/';
} }
@ -242,14 +222,14 @@ export default class MiOS extends EventEmitter {
this.once('signedin', () => { this.once('signedin', () => {
// Init home stream manager // Init home stream manager
this.stream = new HomeStreamManager(this, this.i); this.stream = new HomeStreamManager(this, this.store.state.i);
// Init other stream manager // Init other stream manager
this.streams.localTimelineStream = new LocalTimelineStreamManager(this, this.i); this.streams.localTimelineStream = new LocalTimelineStreamManager(this, this.store.state.i);
this.streams.globalTimelineStream = new GlobalTimelineStreamManager(this, this.i); this.streams.globalTimelineStream = new GlobalTimelineStreamManager(this, this.store.state.i);
this.streams.driveStream = new DriveStreamManager(this, this.i); this.streams.driveStream = new DriveStreamManager(this, this.store.state.i);
this.streams.messagingIndexStream = new MessagingIndexStreamManager(this, this.i); this.streams.messagingIndexStream = new MessagingIndexStreamManager(this, this.store.state.i);
this.streams.othelloStream = new OthelloStreamManager(this, this.i); this.streams.othelloStream = new OthelloStreamManager(this, this.store.state.i);
}); });
//#endregion //#endregion
@ -300,51 +280,29 @@ export default class MiOS extends EventEmitter {
}; };
// フェッチが完了したとき // フェッチが完了したとき
const fetched = me => { const fetched = () => {
this.i = me;
// ローカルストレージにキャッシュ
this.bakeMe();
this.emit('signedin'); this.emit('signedin');
// Finish init // Finish init
callback(); callback();
//#region Note
// Init service worker // Init service worker
if (this.shouldRegisterSw) this.registerSw(); if (this.shouldRegisterSw) this.registerSw();
//#endregion
}; };
// Get cached account data
const cachedMe = JSON.parse(localStorage.getItem('me'));
//#region キャッシュされた設定を復元
const cachedSettings = JSON.parse(localStorage.getItem('settings'));
if (cachedSettings) {
this.store.dispatch('settings/merge', cachedSettings);
}
//#endregion
// キャッシュがあったとき // キャッシュがあったとき
if (cachedMe) { if (this.store.state.i != null) {
if (cachedMe.token == null) { if (this.store.state.i.token == null) {
this.signout(); this.signout();
return; return;
} }
// とりあえずキャッシュされたデータでお茶を濁して(?)おいて、 // とりあえずキャッシュされたデータでお茶を濁して(?)おいて、
fetched(cachedMe); fetched();
// 後から新鮮なデータをフェッチ // 後から新鮮なデータをフェッチ
fetchme(cachedMe.token, freshData => { fetchme(this.store.state.i.token, freshData => {
merge(cachedMe, freshData); this.store.dispatch('mergeMe', freshData);
this.store.dispatch('settings/merge', freshData.clientSettings);
}); });
} else { } else {
// Get token from cookie // Get token from cookie
@ -352,9 +310,8 @@ export default class MiOS extends EventEmitter {
fetchme(i, me => { fetchme(i, me => {
if (me) { if (me) {
this.store.dispatch('settings/merge', me.clientSettings); this.store.dispatch('login', me);
fetched();
fetched(me);
} else { } else {
// Finish init // Finish init
callback(); callback();
@ -375,7 +332,7 @@ export default class MiOS extends EventEmitter {
if (!isSwSupported) return; if (!isSwSupported) return;
// Reject when not signed in to Misskey // Reject when not signed in to Misskey
if (!this.isSignedIn) return; if (!this.store.getters.isSignedIn) return;
// When service worker activated // When service worker activated
navigator.serviceWorker.ready.then(registration => { navigator.serviceWorker.ready.then(registration => {
@ -484,7 +441,7 @@ export default class MiOS extends EventEmitter {
}); });
} else { } else {
// Append a credential // Append a credential
if (this.isSignedIn) (data as any).i = this.i.token; if (this.store.getters.isSignedIn) (data as any).i = this.store.state.i.token;
const req = { const req = {
id: uuid(), id: uuid(),

View File

@ -31,7 +31,7 @@
<div class="body"> <div class="body">
<div class="text"> <div class="text">
<span v-if="p.isHidden" style="opacity: 0.5">(この投稿は非公開です)</span> <span v-if="p.isHidden" style="opacity: 0.5">(この投稿は非公開です)</span>
<mk-note-html v-if="p.text" :text="p.text" :i="os.i"/> <mk-note-html v-if="p.text" :text="p.text" :i="$store.state.i"/>
</div> </div>
<div class="tags" v-if="p.tags && p.tags.length > 0"> <div class="tags" v-if="p.tags && p.tags.length > 0">
<router-link v-for="tag in p.tags" :key="tag" :to="`/search?q=#${tag}`">{{ tag }}</router-link> <router-link v-for="tag in p.tags" :key="tag" :to="`/search?q=#${tag}`">{{ tag }}</router-link>
@ -147,7 +147,7 @@ export default Vue.extend({
// Draw map // Draw map
if (this.p.geo) { if (this.p.geo) {
const shouldShowMap = (this as any).os.isSignedIn ? (this as any).clientSettings.showMaps : true; const shouldShowMap = this.$store.getters.isSignedIn ? this.$store.state.settings.showMaps : true;
if (shouldShowMap) { if (shouldShowMap) {
(this as any).os.getGoogleMaps().then(maps => { (this as any).os.getGoogleMaps().then(maps => {
const uluru = new maps.LatLng(this.p.geo.coordinates[1], this.p.geo.coordinates[0]); const uluru = new maps.LatLng(this.p.geo.coordinates[1], this.p.geo.coordinates[0]);

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="note" :class="{ renote: isRenote, smart: $store.state.device.postStyle == 'smart' }"> <div class="note" :class="{ renote: isRenote, smart: $store.state.device.postStyle == 'smart' }">
<div class="reply-to" v-if="p.reply && (!os.isSignedIn || clientSettings.showReplyTarget)"> <div class="reply-to" v-if="p.reply && (!$store.getters.isSignedIn || $store.state.settings.showReplyTarget)">
<x-sub :note="p.reply"/> <x-sub :note="p.reply"/>
</div> </div>
<div class="renote" v-if="isRenote"> <div class="renote" v-if="isRenote">
@ -43,7 +43,7 @@
<div class="text"> <div class="text">
<span v-if="p.isHidden" style="opacity: 0.5">(この投稿は非公開です)</span> <span v-if="p.isHidden" style="opacity: 0.5">(この投稿は非公開です)</span>
<a class="reply" v-if="p.reply">%fa:reply%</a> <a class="reply" v-if="p.reply">%fa:reply%</a>
<mk-note-html v-if="p.text && !canHideText(p)" :text="p.text" :i="os.i" :class="$style.text"/> <mk-note-html v-if="p.text && !canHideText(p)" :text="p.text" :i="$store.state.i" :class="$style.text"/>
<a class="rp" v-if="p.renote != null">RP:</a> <a class="rp" v-if="p.renote != null">RP:</a>
</div> </div>
<div class="media" v-if="p.media.length > 0"> <div class="media" v-if="p.media.length > 0">
@ -141,7 +141,7 @@ export default Vue.extend({
}, },
created() { created() {
if ((this as any).os.isSignedIn) { if (this.$store.getters.isSignedIn) {
this.connection = (this as any).os.stream.getConnection(); this.connection = (this as any).os.stream.getConnection();
this.connectionId = (this as any).os.stream.use(); this.connectionId = (this as any).os.stream.use();
} }
@ -150,13 +150,13 @@ export default Vue.extend({
mounted() { mounted() {
this.capture(true); this.capture(true);
if ((this as any).os.isSignedIn) { if (this.$store.getters.isSignedIn) {
this.connection.on('_connected_', this.onStreamConnected); this.connection.on('_connected_', this.onStreamConnected);
} }
// Draw map // Draw map
if (this.p.geo) { if (this.p.geo) {
const shouldShowMap = (this as any).os.isSignedIn ? (this as any).clientSettings.showMaps : true; const shouldShowMap = this.$store.getters.isSignedIn ? this.$store.state.settings.showMaps : true;
if (shouldShowMap) { if (shouldShowMap) {
(this as any).os.getGoogleMaps().then(maps => { (this as any).os.getGoogleMaps().then(maps => {
const uluru = new maps.LatLng(this.p.geo.coordinates[1], this.p.geo.coordinates[0]); const uluru = new maps.LatLng(this.p.geo.coordinates[1], this.p.geo.coordinates[0]);
@ -176,7 +176,7 @@ export default Vue.extend({
beforeDestroy() { beforeDestroy() {
this.decapture(true); this.decapture(true);
if ((this as any).os.isSignedIn) { if (this.$store.getters.isSignedIn) {
this.connection.off('_connected_', this.onStreamConnected); this.connection.off('_connected_', this.onStreamConnected);
(this as any).os.stream.dispose(this.connectionId); (this as any).os.stream.dispose(this.connectionId);
} }
@ -186,7 +186,7 @@ export default Vue.extend({
canHideText, canHideText,
capture(withHandler = false) { capture(withHandler = false) {
if ((this as any).os.isSignedIn) { if (this.$store.getters.isSignedIn) {
this.connection.send({ this.connection.send({
type: 'capture', type: 'capture',
id: this.p.id id: this.p.id
@ -196,7 +196,7 @@ export default Vue.extend({
}, },
decapture(withHandler = false) { decapture(withHandler = false) {
if ((this as any).os.isSignedIn) { if (this.$store.getters.isSignedIn) {
this.connection.send({ this.connection.send({
type: 'decapture', type: 'decapture',
id: this.p.id id: this.p.id

View File

@ -121,24 +121,24 @@ export default Vue.extend({
prepend(note, silent = false) { prepend(note, silent = false) {
//#region //#region
const isMyNote = note.userId == (this as any).os.i.id; const isMyNote = note.userId == this.$store.state.i.id;
const isPureRenote = note.renoteId != null && note.text == null && note.mediaIds.length == 0 && note.poll == null; const isPureRenote = note.renoteId != null && note.text == null && note.mediaIds.length == 0 && note.poll == null;
if ((this as any).clientSettings.showMyRenotes === false) { if (this.$store.state.settings.showMyRenotes === false) {
if (isMyNote && isPureRenote) { if (isMyNote && isPureRenote) {
return; return;
} }
} }
if ((this as any).clientSettings.showRenotedMyNotes === false) { if (this.$store.state.settings.showRenotedMyNotes === false) {
if (isPureRenote && (note.renote.userId == (this as any).os.i.id)) { if (isPureRenote && (note.renote.userId == this.$store.state.i.id)) {
return; return;
} }
} }
//#endregion //#endregion
// 稿 // 稿
if ((document.hidden || !this.isScrollTop()) && note.userId !== (this as any).os.i.id) { if ((document.hidden || !this.isScrollTop()) && note.userId !== this.$store.state.i.id) {
this.unreadCount++; this.unreadCount++;
document.title = `(${this.unreadCount}) ${getNoteSummary(note)}`; document.title = `(${this.unreadCount}) ${getNoteSummary(note)}`;
} }
@ -195,7 +195,7 @@ export default Vue.extend({
this.clearNotification(); this.clearNotification();
} }
if ((this as any).clientSettings.fetchOnScroll !== false) { if (this.$store.state.settings.fetchOnScroll !== false) {
// display none // display none
// https://github.com/syuilo/misskey/issues/1569 // https://github.com/syuilo/misskey/issues/1569
// http://d.hatena.ne.jp/favril/20091105/1257403319 // http://d.hatena.ne.jp/favril/20091105/1257403319

View File

@ -86,7 +86,7 @@ export default Vue.extend({
const mention = x.host ? `@${x.username}@${x.host}` : `@${x.username}`; const mention = x.host ? `@${x.username}@${x.host}` : `@${x.username}`;
// //
if (this.os.i.username == x.username && x.host == null) return; if (this.$store.state.i.username == x.username && x.host == null) return;
// //
if (this.text.indexOf(`${mention} `) != -1) return; if (this.text.indexOf(`${mention} `) != -1) return;
@ -194,7 +194,7 @@ export default Vue.extend({
post() { post() {
this.posting = true; this.posting = true;
const viaMobile = (this as any).clientSettings.disableViaMobile !== true; const viaMobile = this.$store.state.settings.disableViaMobile !== true;
(this as any).api('notes/create', { (this as any).api('notes/create', {
text: this.text == '' ? undefined : this.text, text: this.text == '' ? undefined : this.text,
mediaIds: this.files.length > 0 ? this.files.map(f => f.id) : undefined, mediaIds: this.files.length > 0 ? this.files.map(f => f.id) : undefined,

View File

@ -3,7 +3,7 @@
<div class="body"> <div class="body">
<span v-if="note.isHidden" style="opacity: 0.5">(この投稿は非公開です)</span> <span v-if="note.isHidden" style="opacity: 0.5">(この投稿は非公開です)</span>
<a class="reply" v-if="note.replyId">%fa:reply%</a> <a class="reply" v-if="note.replyId">%fa:reply%</a>
<mk-note-html v-if="note.text" :text="note.text" :i="os.i"/> <mk-note-html v-if="note.text" :text="note.text" :i="$store.state.i"/>
<a class="rp" v-if="note.renoteId">RP: ...</a> <a class="rp" v-if="note.renoteId">RP: ...</a>
</div> </div>
<details v-if="note.media.length > 0"> <details v-if="note.media.length > 0">

View File

@ -3,7 +3,7 @@
<mk-special-message/> <mk-special-message/>
<div class="main" ref="main"> <div class="main" ref="main">
<div class="backdrop"></div> <div class="backdrop"></div>
<p ref="welcomeback" v-if="os.isSignedIn">おかえりなさい<b>{{ os.i | userName }}</b>さん</p> <p ref="welcomeback" v-if="$store.getters.isSignedIn">おかえりなさい<b>{{ $store.state.i | userName }}</b>さん</p>
<div class="content" ref="mainContainer"> <div class="content" ref="mainContainer">
<button class="nav" @click="$parent.isDrawerOpening = true">%fa:bars%</button> <button class="nav" @click="$parent.isDrawerOpening = true">%fa:bars%</button>
<template v-if="hasUnreadNotifications || hasUnreadMessagingMessages || hasGameInvitations">%fa:circle%</template> <template v-if="hasUnreadNotifications || hasUnreadMessagingMessages || hasGameInvitations">%fa:circle%</template>
@ -35,7 +35,7 @@ export default Vue.extend({
mounted() { mounted() {
this.$store.commit('setUiHeaderHeight', 48); this.$store.commit('setUiHeaderHeight', 48);
if ((this as any).os.isSignedIn) { if (this.$store.getters.isSignedIn) {
this.connection = (this as any).os.stream.getConnection(); this.connection = (this as any).os.stream.getConnection();
this.connectionId = (this as any).os.stream.use(); this.connectionId = (this as any).os.stream.use();
@ -60,10 +60,10 @@ export default Vue.extend({
} }
}); });
const ago = (new Date().getTime() - new Date((this as any).os.i.lastUsedAt).getTime()) / 1000; const ago = (new Date().getTime() - new Date(this.$store.state.i.lastUsedAt).getTime()) / 1000;
const isHisasiburi = ago >= 3600; const isHisasiburi = ago >= 3600;
(this as any).os.i.lastUsedAt = new Date(); this.$store.state.i.lastUsedAt = new Date();
(this as any).os.bakeMe();
if (isHisasiburi) { if (isHisasiburi) {
(this.$refs.welcomeback as any).style.display = 'block'; (this.$refs.welcomeback as any).style.display = 'block';
(this.$refs.main as any).style.overflow = 'hidden'; (this.$refs.main as any).style.overflow = 'hidden';
@ -109,7 +109,7 @@ export default Vue.extend({
} }
}, },
beforeDestroy() { beforeDestroy() {
if ((this as any).os.isSignedIn) { if (this.$store.getters.isSignedIn) {
this.connection.off('read_all_notifications', this.onReadAllNotifications); this.connection.off('read_all_notifications', this.onReadAllNotifications);
this.connection.off('unread_notification', this.onUnreadNotification); this.connection.off('unread_notification', this.onUnreadNotification);
this.connection.off('read_all_messaging_messages', this.onReadAllMessagingMessages); this.connection.off('read_all_messaging_messages', this.onReadAllMessagingMessages);

View File

@ -9,9 +9,9 @@
</transition> </transition>
<transition name="nav"> <transition name="nav">
<div class="body" v-if="isOpen"> <div class="body" v-if="isOpen">
<router-link class="me" v-if="os.isSignedIn" :to="`/@${os.i.username}`"> <router-link class="me" v-if="$store.getters.isSignedIn" :to="`/@${$store.state.i.username}`">
<img class="avatar" :src="`${os.i.avatarUrl}?thumbnail&size=128`" alt="avatar"/> <img class="avatar" :src="`${$store.state.i.avatarUrl}?thumbnail&size=128`" alt="avatar"/>
<p class="name">{{ os.i | userName }}</p> <p class="name">{{ $store.state.i | userName }}</p>
</router-link> </router-link>
<div class="links"> <div class="links">
<ul> <ul>
@ -55,7 +55,7 @@ export default Vue.extend({
}; };
}, },
mounted() { mounted() {
if ((this as any).os.isSignedIn) { if (this.$store.getters.isSignedIn) {
this.connection = (this as any).os.stream.getConnection(); this.connection = (this as any).os.stream.getConnection();
this.connectionId = (this as any).os.stream.use(); this.connectionId = (this as any).os.stream.use();
@ -82,7 +82,7 @@ export default Vue.extend({
} }
}, },
beforeDestroy() { beforeDestroy() {
if ((this as any).os.isSignedIn) { if (this.$store.getters.isSignedIn) {
this.connection.off('read_all_notifications', this.onReadAllNotifications); this.connection.off('read_all_notifications', this.onReadAllNotifications);
this.connection.off('unread_notification', this.onUnreadNotification); this.connection.off('unread_notification', this.onUnreadNotification);
this.connection.off('read_all_messaging_messages', this.onReadAllMessagingMessages); this.connection.off('read_all_messaging_messages', this.onReadAllMessagingMessages);

View File

@ -8,7 +8,7 @@
<div class="content"> <div class="content">
<slot></slot> <slot></slot>
</div> </div>
<mk-stream-indicator v-if="os.isSignedIn"/> <mk-stream-indicator v-if="$store.getters.isSignedIn"/>
</div> </div>
</template> </template>
@ -32,7 +32,7 @@ export default Vue.extend({
}; };
}, },
mounted() { mounted() {
if ((this as any).os.isSignedIn) { if (this.$store.getters.isSignedIn) {
this.connection = (this as any).os.stream.getConnection(); this.connection = (this as any).os.stream.getConnection();
this.connectionId = (this as any).os.stream.use(); this.connectionId = (this as any).os.stream.use();
@ -40,7 +40,7 @@ export default Vue.extend({
} }
}, },
beforeDestroy() { beforeDestroy() {
if ((this as any).os.isSignedIn) { if (this.$store.getters.isSignedIn) {
this.connection.off('notification', this.onNotification); this.connection.off('notification', this.onNotification);
(this as any).os.stream.dispose(this.connectionId); (this as any).os.stream.dispose(this.connectionId);
} }

View File

@ -43,7 +43,7 @@ export default Vue.extend({
methods: { methods: {
init() { init() {
if (this.connection) this.connection.close(); if (this.connection) this.connection.close();
this.connection = new UserListStream((this as any).os, (this as any).os.i, this.list.id); this.connection = new UserListStream((this as any).os, this.$store.state.i, this.list.id);
this.connection.on('note', this.onNote); this.connection.on('note', this.onNote);
this.connection.on('userAdded', this.onUserAdded); this.connection.on('userAdded', this.onUserAdded);
this.connection.on('userRemoved', this.onUserRemoved); this.connection.on('userRemoved', this.onUserRemoved);
@ -58,8 +58,8 @@ export default Vue.extend({
(this as any).api('notes/user-list-timeline', { (this as any).api('notes/user-list-timeline', {
listId: this.list.id, listId: this.list.id,
limit: fetchLimit + 1, limit: fetchLimit + 1,
includeMyRenotes: (this as any).clientSettings.showMyRenotes, includeMyRenotes: this.$store.state.settings.showMyRenotes,
includeRenotedMyNotes: (this as any).clientSettings.showRenotedMyNotes includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes
}).then(notes => { }).then(notes => {
if (notes.length == fetchLimit + 1) { if (notes.length == fetchLimit + 1) {
notes.pop(); notes.pop();
@ -81,8 +81,8 @@ export default Vue.extend({
listId: this.list.id, listId: this.list.id,
limit: fetchLimit + 1, limit: fetchLimit + 1,
untilId: (this.$refs.timeline as any).tail().id, untilId: (this.$refs.timeline as any).tail().id,
includeMyRenotes: (this as any).clientSettings.showMyRenotes, includeMyRenotes: this.$store.state.settings.showMyRenotes,
includeRenotedMyNotes: (this as any).clientSettings.showRenotedMyNotes includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes
}); });
promise.then(notes => { promise.then(notes => {

View File

@ -2,7 +2,7 @@
<div class="mk-users-list"> <div class="mk-users-list">
<nav> <nav>
<span :data-active="mode == 'all'" @click="mode = 'all'">%i18n:@all%<span>{{ count }}</span></span> <span :data-active="mode == 'all'" @click="mode = 'all'">%i18n:@all%<span>{{ count }}</span></span>
<span v-if="os.isSignedIn && youKnowCount" :data-active="mode == 'iknow'" @click="mode = 'iknow'">%i18n:@known%<span>{{ youKnowCount }}</span></span> <span v-if="$store.getters.isSignedIn && youKnowCount" :data-active="mode == 'iknow'" @click="mode = 'iknow'">%i18n:@known%<span>{{ youKnowCount }}</span></span>
</nav> </nav>
<div class="users" v-if="!fetching && users.length != 0"> <div class="users" v-if="!fetching && users.length != 0">
<mk-user-preview v-for="u in users" :user="u" :key="u.id"/> <mk-user-preview v-for="u in users" :user="u" :key="u.id"/>

View File

@ -38,7 +38,7 @@ export default Vue.extend({
computed: { computed: {
alone(): boolean { alone(): boolean {
return (this as any).os.i.followingCount == 0; return this.$store.state.i.followingCount == 0;
}, },
stream(): any { stream(): any {
@ -92,8 +92,8 @@ export default Vue.extend({
(this as any).api(this.endpoint, { (this as any).api(this.endpoint, {
limit: fetchLimit + 1, limit: fetchLimit + 1,
untilDate: this.date ? this.date.getTime() : undefined, untilDate: this.date ? this.date.getTime() : undefined,
includeMyRenotes: (this as any).clientSettings.showMyRenotes, includeMyRenotes: this.$store.state.settings.showMyRenotes,
includeRenotedMyNotes: (this as any).clientSettings.showRenotedMyNotes includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes
}).then(notes => { }).then(notes => {
if (notes.length == fetchLimit + 1) { if (notes.length == fetchLimit + 1) {
notes.pop(); notes.pop();
@ -114,8 +114,8 @@ export default Vue.extend({
const promise = (this as any).api(this.endpoint, { const promise = (this as any).api(this.endpoint, {
limit: fetchLimit + 1, limit: fetchLimit + 1,
untilId: (this.$refs.timeline as any).tail().id, untilId: (this.$refs.timeline as any).tail().id,
includeMyRenotes: (this as any).clientSettings.showMyRenotes, includeMyRenotes: this.$store.state.settings.showMyRenotes,
includeRenotedMyNotes: (this as any).clientSettings.showRenotedMyNotes includeRenotedMyNotes: this.$store.state.settings.showRenotedMyNotes
}); });
promise.then(notes => { promise.then(notes => {

View File

@ -87,7 +87,7 @@ export default Vue.extend({
if (this.src == 'list') { if (this.src == 'list') {
this.list = this.$store.state.device.tl.arg; this.list = this.$store.state.device.tl.arg;
} }
} else if ((this as any).os.i.followingCount == 0) { } else if (this.$store.state.i.followingCount == 0) {
this.src = 'local'; this.src = 'local';
} }
}, },

View File

@ -1,5 +1,5 @@
<template> <template>
<component :is="os.isSignedIn ? 'home' : 'welcome'"></component> <component :is="$store.getters.isSignedIn ? 'home' : 'welcome'"></component>
</template> </template>
<script lang="ts"> <script lang="ts">

View File

@ -17,22 +17,22 @@
</div> </div>
<div> <div>
<md-switch v-model="clientSettings.circleIcons" @change="onChangeCircleIcons">%i18n:@circle-icons%</md-switch> <md-switch v-model="$store.state.settings.circleIcons" @change="onChangeCircleIcons">%i18n:@circle-icons%</md-switch>
</div> </div>
<div> <div>
<div class="md-body-2">%i18n:@timeline%</div> <div class="md-body-2">%i18n:@timeline%</div>
<div> <div>
<md-switch v-model="clientSettings.showReplyTarget" @change="onChangeShowReplyTarget">%i18n:@show-reply-target%</md-switch> <md-switch v-model="$store.state.settings.showReplyTarget" @change="onChangeShowReplyTarget">%i18n:@show-reply-target%</md-switch>
</div> </div>
<div> <div>
<md-switch v-model="clientSettings.showMyRenotes" @change="onChangeShowMyRenotes">%i18n:@show-my-renotes%</md-switch> <md-switch v-model="$store.state.settings.showMyRenotes" @change="onChangeShowMyRenotes">%i18n:@show-my-renotes%</md-switch>
</div> </div>
<div> <div>
<md-switch v-model="clientSettings.showRenotedMyNotes" @change="onChangeShowRenotedMyNotes">%i18n:@show-renoted-my-notes%</md-switch> <md-switch v-model="$store.state.settings.showRenotedMyNotes" @change="onChangeShowRenotedMyNotes">%i18n:@show-renoted-my-notes%</md-switch>
</div> </div>
</div> </div>
@ -52,11 +52,11 @@
<md-card-content> <md-card-content>
<div> <div>
<md-switch v-model="clientSettings.fetchOnScroll" @change="onChangeFetchOnScroll">%i18n:@fetch-on-scroll%</md-switch> <md-switch v-model="$store.state.settings.fetchOnScroll" @change="onChangeFetchOnScroll">%i18n:@fetch-on-scroll%</md-switch>
</div> </div>
<div> <div>
<md-switch v-model="clientSettings.disableViaMobile" @change="onChangeDisableViaMobile">%i18n:@disable-via-mobile%</md-switch> <md-switch v-model="$store.state.settings.disableViaMobile" @change="onChangeDisableViaMobile">%i18n:@disable-via-mobile%</md-switch>
</div> </div>
<div> <div>
@ -64,7 +64,7 @@
</div> </div>
<div> <div>
<md-switch v-model="clientSettings.loadRemoteMedia" @change="onChangeLoadRemoteMedia">%i18n:@load-remote-media%</md-switch> <md-switch v-model="$store.state.settings.loadRemoteMedia" @change="onChangeLoadRemoteMedia">%i18n:@load-remote-media%</md-switch>
</div> </div>
<div> <div>
@ -100,11 +100,11 @@
</md-card-header> </md-card-header>
<md-card-content> <md-card-content>
<p class="account" v-if="os.i.twitter"><a :href="`https://twitter.com/${os.i.twitter.screenName}`" target="_blank">@{{ os.i.twitter.screenName }}</a></p> <p class="account" v-if="$store.state.i.twitter"><a :href="`https://twitter.com/${$store.state.i.twitter.screenName}`" target="_blank">@{{ $store.state.i.twitter.screenName }}</a></p>
<p> <p>
<a :href="`${apiUrl}/connect/twitter`" target="_blank">{{ os.i.twitter ? '%i18n:@twitter-reconnect%' : '%i18n:@twitter-connect%' }}</a> <a :href="`${apiUrl}/connect/twitter`" target="_blank">{{ $store.state.i.twitter ? '%i18n:@twitter-reconnect%' : '%i18n:@twitter-connect%' }}</a>
<span v-if="os.i.twitter"> or </span> <span v-if="$store.state.i.twitter"> or </span>
<a :href="`${apiUrl}/disconnect/twitter`" target="_blank" v-if="os.i.twitter">%i18n:@twitter-disconnect%</a> <a :href="`${apiUrl}/disconnect/twitter`" target="_blank" v-if="$store.state.i.twitter">%i18n:@twitter-disconnect%</a>
</p> </p>
</md-card-content> </md-card-content>
</md-card> </md-card>
@ -156,7 +156,7 @@ export default Vue.extend({
computed: { computed: {
name(): string { name(): string {
return Vue.filter('userName')((this as any).os.i); return Vue.filter('userName')(this.$store.state.i);
}, },
darkmode: { darkmode: {

View File

@ -82,15 +82,15 @@ export default Vue.extend({
}, },
created() { created() {
this.name = (this as any).os.i.name || ''; this.name = this.$store.state.i.name || '';
this.username = (this as any).os.i.username; this.username = this.$store.state.i.username;
this.location = (this as any).os.i.profile.location; this.location = this.$store.state.i.profile.location;
this.description = (this as any).os.i.description; this.description = this.$store.state.i.description;
this.birthday = (this as any).os.i.profile.birthday; this.birthday = this.$store.state.i.profile.birthday;
this.avatarId = (this as any).os.i.avatarId; this.avatarId = this.$store.state.i.avatarId;
this.bannerId = (this as any).os.i.bannerId; this.bannerId = this.$store.state.i.bannerId;
this.isBot = (this as any).os.i.isBot; this.isBot = this.$store.state.i.isBot;
this.isCat = (this as any).os.i.isCat; this.isCat = this.$store.state.i.isCat;
}, },
methods: { methods: {
@ -99,7 +99,7 @@ export default Vue.extend({
const data = new FormData(); const data = new FormData();
data.append('file', file); data.append('file', file);
data.append('i', (this as any).os.i.token); data.append('i', this.$store.state.i.token);
fetch(apiUrl + '/drive/files/create', { fetch(apiUrl + '/drive/files/create', {
method: 'POST', method: 'POST',
@ -121,7 +121,7 @@ export default Vue.extend({
const data = new FormData(); const data = new FormData();
data.append('file', file); data.append('file', file);
data.append('i', (this as any).os.i.token); data.append('i', this.$store.state.i.token);
fetch(apiUrl + '/drive/files/create', { fetch(apiUrl + '/drive/files/create', {
method: 'POST', method: 'POST',
@ -152,10 +152,10 @@ export default Vue.extend({
isCat: this.isCat isCat: this.isCat
}).then(i => { }).then(i => {
this.saving = false; this.saving = false;
(this as any).os.i.avatarId = i.avatarId; this.$store.state.i.avatarId = i.avatarId;
(this as any).os.i.avatarUrl = i.avatarUrl; this.$store.state.i.avatarUrl = i.avatarUrl;
(this as any).os.i.bannerId = i.bannerId; this.$store.state.i.bannerId = i.bannerId;
(this as any).os.i.bannerUrl = i.bannerUrl; this.$store.state.i.bannerUrl = i.bannerUrl;
alert('%i18n:@saved%'); alert('%i18n:@saved%');
}); });

View File

@ -11,7 +11,7 @@
<a class="avatar"> <a class="avatar">
<img :src="user.avatarUrl" alt="avatar"/> <img :src="user.avatarUrl" alt="avatar"/>
</a> </a>
<mk-follow-button v-if="os.isSignedIn && os.i.id != user.id" :user="user"/> <mk-follow-button v-if="$store.getters.isSignedIn && $store.state.i.id != user.id" :user="user"/>
</div> </div>
<div class="title"> <div class="title">
<h1>{{ user | userName }}</h1> <h1>{{ user | userName }}</h1>

View File

@ -25,7 +25,7 @@
<x-friends :user="user"/> <x-friends :user="user"/>
</div> </div>
</section> </section>
<section class="followers-you-know" v-if="os.isSignedIn && os.i.id !== user.id"> <section class="followers-you-know" v-if="$store.getters.isSignedIn && $store.state.i.id !== user.id">
<h2>%fa:users%%i18n:@followers-you-know%</h2> <h2>%fa:users%%i18n:@followers-you-know%</h2>
<div> <div>
<x-followers-you-know :user="user"/> <x-followers-you-know :user="user"/>

View File

@ -3,7 +3,7 @@
<mk-widget-container :show-header="!props.compact"> <mk-widget-container :show-header="!props.compact">
<template slot="header">%fa:chart-bar%アクティビティ</template> <template slot="header">%fa:chart-bar%アクティビティ</template>
<div :class="$style.body"> <div :class="$style.body">
<mk-activity :user="os.i"/> <mk-activity :user="$store.state.i"/>
</div> </div>
</mk-widget-container> </mk-widget-container>
</div> </div>

View File

@ -2,13 +2,13 @@
<div class="mkw-profile"> <div class="mkw-profile">
<mk-widget-container> <mk-widget-container>
<div :class="$style.banner" <div :class="$style.banner"
:style="os.i.bannerUrl ? `background-image: url(${os.i.bannerUrl}?thumbnail&size=256)` : ''" :style="$store.state.i.bannerUrl ? `background-image: url(${$store.state.i.bannerUrl}?thumbnail&size=256)` : ''"
></div> ></div>
<img :class="$style.avatar" <img :class="$style.avatar"
:src="`${os.i.avatarUrl}?thumbnail&size=96`" :src="`${$store.state.i.avatarUrl}?thumbnail&size=96`"
alt="avatar" alt="avatar"
/> />
<router-link :class="$style.name" :to="os.i | userPage">{{ os.i | userName }}</router-link> <router-link :class="$style.name" :to="$store.state.i | userPage">{{ $store.state.i | userName }}</router-link>
</mk-widget-container> </mk-widget-container>
</div> </div>
</template> </template>

View File

@ -2,6 +2,7 @@ import Vuex from 'vuex';
import createPersistedState from 'vuex-persistedstate'; import createPersistedState from 'vuex-persistedstate';
import MiOS from './mios'; import MiOS from './mios';
import { hostname } from './config';
const defaultSettings = { const defaultSettings = {
home: [], home: [],
@ -33,23 +34,29 @@ const defaultDeviceSettings = {
}; };
export default (os: MiOS) => new Vuex.Store({ export default (os: MiOS) => new Vuex.Store({
plugins: [store => { plugins: [createPersistedState({
store.subscribe((mutation, state) => { paths: ['i', 'device', 'settings']
if (mutation.type.startsWith('settings/')) {
localStorage.setItem('settings', JSON.stringify(state.settings));
}
});
}, createPersistedState({
paths: ['device'],
filter: mut => mut.type.startsWith('device/')
})], })],
state: { state: {
i: null,
indicate: false, indicate: false,
uiHeaderHeight: 0 uiHeaderHeight: 0
}, },
getters: {
isSignedIn: state => state.i != null
},
mutations: { mutations: {
updateI(state, x) {
state.i = x;
},
updateIKeyValue(state, x) {
state.i[x.key] = x.value;
},
indicate(state, x) { indicate(state, x) {
state.indicate = x; state.indicate = x;
}, },
@ -59,6 +66,28 @@ export default (os: MiOS) => new Vuex.Store({
} }
}, },
actions: {
login(ctx, i) {
ctx.commit('updateI', i);
ctx.dispatch('settings/merge', i.clientSettings);
},
logout(ctx) {
ctx.commit('updateI', null);
document.cookie = `i=; domain=${hostname}; expires=Thu, 01 Jan 1970 00:00:01 GMT;`;
},
mergeMe(ctx, me) {
Object.entries(me).forEach(([key, value]) => {
ctx.commit('updateIKeyValue', { key, value });
});
if (me.clientSettings) {
ctx.dispatch('settings/merge', me.clientSettings);
}
},
},
modules: { modules: {
device: { device: {
namespaced: true, namespaced: true,
@ -134,7 +163,7 @@ export default (os: MiOS) => new Vuex.Store({
set(ctx, x) { set(ctx, x) {
ctx.commit('set', x); ctx.commit('set', x);
if (os.isSignedIn) { if (ctx.rootGetters.isSignedIn) {
os.api('i/update_client_setting', { os.api('i/update_client_setting', {
name: x.key, name: x.key,
value: x.value value: x.value