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

View file

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

View file

@ -32,7 +32,7 @@ export default Vue.extend({
? `rgb(${ this.user.avatarColor.join(',') })`
: null,
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"/>
</button>
<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">
<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"/>
@ -42,7 +42,7 @@ export default Vue.extend({
},
computed: {
isMe(): boolean {
return this.message.userId == (this as any).os.i.id;
return this.message.userId == this.$store.state.i.id;
},
urls(): string[] {
if (this.message.text) {

View file

@ -72,7 +72,7 @@ export default Vue.extend({
},
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('read', this.onRead);
@ -164,7 +164,7 @@ export default Vue.extend({
const isBottom = this.isBottom();
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({
type: 'read',
id: message.id
@ -176,7 +176,7 @@ export default Vue.extend({
this.$nextTick(() => {
this.scrollToBottom();
});
} else if (message.userId != (this as any).os.i.id) {
} else if (message.userId != this.$store.state.i.id) {
// Notify
this.notifyNewMessage();
}
@ -229,7 +229,7 @@ export default Vue.extend({
onVisibilitychange() {
if (document.hidden) return;
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({
type: 'read',
id: message.id

View file

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

View file

@ -3,7 +3,7 @@
<div class="backdrop" ref="backdrop" @click="close"></div>
<div class="popover" :class="{ compact }" ref="popover">
<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>
</div>
</div>

View file

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

View file

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

View file

@ -1,13 +1,13 @@
<template>
<div class="mk-twitter-setting">
<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>
<a :href="`${apiUrl}/connect/twitter`" target="_blank" @click.prevent="connect">{{ os.i.twitter ? '%i18n:@reconnect%' : '%i18n:@connect%' }}</a>
<span v-if="os.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}/connect/twitter`" target="_blank" @click.prevent="connect">{{ $store.state.i.twitter ? '%i18n:@reconnect%' : '%i18n:@connect%' }}</a>
<span v-if="$store.state.i.twitter"> or </span>
<a :href="`${apiUrl}/disconnect/twitter`" target="_blank" v-if="$store.state.i.twitter" @click.prevent="disconnect">%i18n:@disconnect%</a>
</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>
</template>
@ -24,8 +24,8 @@ export default Vue.extend({
};
},
mounted() {
this.$watch('os.i', () => {
if ((this as any).os.i.twitter) {
this.$watch('$store.state.i', () => {
if (this.$store.state.i.twitter) {
if (this.form) this.form.close();
}
}, {

View file

@ -50,7 +50,7 @@ export default Vue.extend({
reader.readAsDataURL(file);
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);
if (folder) data.append('folderId', folder);

View file

@ -1,18 +1,17 @@
import OS from '../../mios';
import { url } from '../../config';
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) => {
const o = opts || {};
if (document.body.clientWidth > 800) {
const w = new MkChooseFileFromDriveWindow({
propsData: {
title: o.title,
multiple: o.multiple,
initFolder: o.currentFolder
}
}).$mount();
const w = os.new(MkChooseFileFromDriveWindow, {
title: o.title,
multiple: o.multiple,
initFolder: o.currentFolder
});
w.$once('selected', file => {
res(file);
});
@ -27,4 +26,4 @@ export default function(opts) {
'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';
export default function(opts) {
export default (os: OS) => opts => {
return new Promise((res, rej) => {
const o = opts || {};
const w = new MkChooseFolderFromDriveWindow({
propsData: {
title: o.title,
initFolder: o.currentFolder
}
}).$mount();
const w = os.new(MkChooseFolderFromDriveWindow, {
title: o.title,
initFolder: o.currentFolder
});
w.$once('selected', folder => {
res(folder);
});
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) => {
const fileSelected = file => {
const w = new CropWindow({
propsData: {
image: file,
title: 'アバターとして表示する部分を選択',
aspectRatio: 1 / 1
}
}).$mount();
const w = os.new(CropWindow, {
image: file,
title: 'アバターとして表示する部分を選択',
aspectRatio: 1 / 1
});
w.$once('cropped', blob => {
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');
os.api('drive/folders/find', {
@ -42,11 +40,9 @@ export default (os: OS) => (cb, file = null) => {
};
const upload = (data, folder) => {
const dialog = new ProgressDialog({
propsData: {
title: '新しいアバターをアップロードしています'
}
}).$mount();
const dialog = os.new(ProgressDialog, {
title: '新しいアバターをアップロードしています'
});
document.body.appendChild(dialog.$el);
if (folder) data.append('folderId', folder.id);
@ -70,8 +66,14 @@ export default (os: OS) => (cb, file = null) => {
os.api('i/update', {
avatarId: file.id
}).then(i => {
os.i.avatarId = i.avatarId;
os.i.avatarUrl = i.avatarUrl;
os.store.commit('updateIKeyValue', {
key: 'avatarId',
value: i.avatarId
});
os.store.commit('updateIKeyValue', {
key: 'avatarUrl',
value: i.avatarUrl
});
os.apis.dialog({
title: '%fa:info-circle%アバターを更新しました',

View file

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

View file

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

View file

@ -9,10 +9,10 @@
@contextmenu.prevent.stop="onContextmenu"
: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>
</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>
</div>
<div class="thumbnail" ref="thumbnail" :style="`background-color: ${ background }`">

View file

@ -51,7 +51,7 @@
<div class="main">
<a @click="hint">カスタマイズのヒント</a>
<div>
<mk-post-form v-if="clientSettings.showPostFormOnTopOfTl"/>
<mk-post-form v-if="$store.state.settings.showPostFormOnTopOfTl"/>
<mk-timeline ref="tl" @loaded="onTlLoaded"/>
</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"/>
</div>
<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-mentions @loaded="onTlLoaded" v-if="mode == 'mentions'"/>
</div>

View file

@ -16,7 +16,7 @@
<div class="body">
<div class="text">
<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 class="media" v-if="note.mediaIds.length > 0">
<mk-media-list :media-list="note.media"/>

View file

@ -39,7 +39,7 @@
<div class="body">
<div class="text">
<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 class="media" v-if="p.media.length > 0">
<mk-media-list :media-list="p.media" :raw="true"/>
@ -158,7 +158,7 @@ export default Vue.extend({
// Draw map
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) {
(this as any).os.getGoogleMaps().then(maps => {
const uluru = new maps.LatLng(this.p.geo.coordinates[1], this.p.geo.coordinates[0]);

View file

@ -1,6 +1,6 @@
<template>
<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"/>
</div>
<div class="renote" v-if="isRenote">
@ -43,7 +43,7 @@
<div class="text">
<span v-if="p.isHidden" style="opacity: 0.5">(この投稿は非公開です)</span>
<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>
</div>
<div class="media" v-if="p.media.length > 0">
@ -166,7 +166,7 @@ export default Vue.extend({
},
created() {
if ((this as any).os.isSignedIn) {
if (this.$store.getters.isSignedIn) {
this.connection = (this as any).os.stream.getConnection();
this.connectionId = (this as any).os.stream.use();
}
@ -175,13 +175,13 @@ export default Vue.extend({
mounted() {
this.capture(true);
if ((this as any).os.isSignedIn) {
if (this.$store.getters.isSignedIn) {
this.connection.on('_connected_', this.onStreamConnected);
}
// Draw map
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) {
(this as any).os.getGoogleMaps().then(maps => {
const uluru = new maps.LatLng(this.p.geo.coordinates[1], this.p.geo.coordinates[0]);
@ -201,7 +201,7 @@ export default Vue.extend({
beforeDestroy() {
this.decapture(true);
if ((this as any).os.isSignedIn) {
if (this.$store.getters.isSignedIn) {
this.connection.off('_connected_', this.onStreamConnected);
(this as any).os.stream.dispose(this.connectionId);
}
@ -211,7 +211,7 @@ export default Vue.extend({
canHideText,
capture(withHandler = false) {
if ((this as any).os.isSignedIn) {
if (this.$store.getters.isSignedIn) {
this.connection.send({
type: 'capture',
id: this.p.id
@ -221,7 +221,7 @@ export default Vue.extend({
},
decapture(withHandler = false) {
if ((this as any).os.isSignedIn) {
if (this.$store.getters.isSignedIn) {
this.connection.send({
type: 'decapture',
id: this.p.id

View file

@ -118,24 +118,24 @@ export default Vue.extend({
prepend(note, silent = false) {
//#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;
if ((this as any).clientSettings.showMyRenotes === false) {
if (this.$store.state.settings.showMyRenotes === false) {
if (isMyNote && isPureRenote) {
return;
}
}
if ((this as any).clientSettings.showRenotedMyNotes === false) {
if (isPureRenote && (note.renote.userId == (this as any).os.i.id)) {
if (this.$store.state.settings.showRenotedMyNotes === false) {
if (isPureRenote && (note.renote.userId == this.$store.state.i.id)) {
return;
}
}
//#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++;
document.title = `(${this.unreadCount}) ${getNoteSummary(note)}`;
}
@ -199,7 +199,7 @@ export default Vue.extend({
this.clearNotification();
}
if ((this as any).clientSettings.fetchOnScroll !== false) {
if (this.$store.state.settings.fetchOnScroll !== false) {
const current = window.scrollY + window.innerHeight;
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}`;
//
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;

View file

@ -2,8 +2,8 @@
<div class="2fa">
<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>
<p v-if="!data && !os.i.twoFactorEnabled"><button @click="register" class="ui primary">%i18n:@register%</button></p>
<template v-if="os.i.twoFactorEnabled">
<p v-if="!data && !$store.state.i.twoFactorEnabled"><button @click="register" class="ui primary">%i18n:@register%</button></p>
<template v-if="$store.state.i.twoFactorEnabled">
<p>%i18n:@already-registered%</p>
<button @click="unregister" class="ui">%i18n:@unregister%</button>
</template>
@ -54,7 +54,7 @@ export default Vue.extend({
password: password
}).then(() => {
(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
}).then(() => {
(this as any).apis.notify('%i18n:@success%');
(this as any).os.i.twoFactorEnabled = true;
this.$store.state.i.twoFactorEnabled = true;
}).catch(() => {
(this as any).apis.notify('%i18n:@failed%');
});

View file

@ -1,6 +1,6 @@
<template>
<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>
<div class="ui info warn"><p>%fa:exclamation-triangle%%i18n:@caution%</p></div>
<p>%i18n:@regeneration-of-token%</p>

View file

@ -2,7 +2,7 @@
<div class="profile">
<label class="avatar ui from group">
<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>
</label>
<label class="ui from group">
@ -24,8 +24,8 @@
<button class="ui primary" @click="save">%i18n:@save%</button>
<section>
<h2>その他</h2>
<mk-switch v-model="os.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.isBot" @change="onChangeIsBot" text="%i18n:@is-bot%"/>
<mk-switch v-model="$store.state.i.isCat" @change="onChangeIsCat" text="%i18n:@is-cat%"/>
</section>
</div>
</template>
@ -43,10 +43,10 @@ export default Vue.extend({
};
},
created() {
this.name = (this as any).os.i.name || '';
this.location = (this as any).os.i.profile.location;
this.description = (this as any).os.i.description;
this.birthday = (this as any).os.i.profile.birthday;
this.name = this.$store.state.i.name || '';
this.location = this.$store.state.i.profile.location;
this.description = this.$store.state.i.description;
this.birthday = this.$store.state.i.profile.birthday;
},
methods: {
updateAvatar() {
@ -64,12 +64,12 @@ export default Vue.extend({
},
onChangeIsBot() {
(this as any).api('i/update', {
isBot: (this as any).os.i.isBot
isBot: this.$store.state.i.isBot
});
},
onChangeIsCat() {
(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'">
<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>
</mk-switch>
<mk-switch v-model="autoPopout" text="%i18n:@auto-popout%">
@ -41,14 +41,14 @@
</div>
<div class="div">
<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="clientSettings.gradientWindowHeader" @change="onChangeGradientWindowHeader" text="%i18n:@gradient-window-header%"/>
<mk-switch v-model="$store.state.settings.circleIcons" @change="onChangeCircleIcons" text="%i18n:@circle-icons%"/>
<mk-switch v-model="$store.state.settings.gradientWindowHeader" @change="onChangeGradientWindowHeader" text="%i18n:@gradient-window-header%"/>
</div>
<mk-switch v-model="clientSettings.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="clientSettings.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="clientSettings.showMaps" @change="onChangeShowMaps" text="%i18n:@show-maps%">
<mk-switch v-model="$store.state.settings.showPostFormOnTopOfTl" @change="onChangeShowPostFormOnTopOfTl" text="%i18n:@post-form-on-timeline%"/>
<mk-switch v-model="$store.state.settings.showReplyTarget" @change="onChangeShowReplyTarget" text="%i18n:@show-reply-target%"/>
<mk-switch v-model="$store.state.settings.showMyRenotes" @change="onChangeShowMyRenotes" text="%i18n:@show-my-renotes%"/>
<mk-switch v-model="$store.state.settings.showRenotedMyNotes" @change="onChangeShowRenotedMyNotes" text="%i18n:@show-renoted-my-notes%"/>
<mk-switch v-model="$store.state.settings.showMaps" @change="onChangeShowMaps" text="%i18n:@show-maps%">
<span>%i18n:@show-maps-desc%</span>
</mk-switch>
</section>
@ -72,7 +72,7 @@
<section class="web" v-show="page == 'web'">
<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 class="web" v-show="page == 'web'">
@ -100,7 +100,7 @@
<section class="notification" v-show="page == 'notification'">
<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>
</mk-switch>
</section>

View file

@ -3,7 +3,7 @@
<div class="body">
<span v-if="note.isHidden" style="opacity: 0.5">%i18n:@hidden%</span>
<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>
</div>
<details v-if="note.media.length > 0">

View file

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

View file

@ -47,7 +47,7 @@ export default Vue.extend({
if (this.src == 'list') {
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';
}
},

View file

@ -1,14 +1,14 @@
<template>
<div class="account">
<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>
<mk-avatar class="avatar" :user="os.i"/>
<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="$store.state.i"/>
</button>
<transition name="zoom-in-top">
<div class="menu" v-if="isOpen">
<ul>
<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 @click="drive">
<p>%fa:cloud%<span>%i18n:@drive%</span>%fa:angle-right%</p>

View file

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

View file

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

View file

@ -4,16 +4,16 @@
<div class="main" ref="main">
<div class="backdrop"></div>
<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="left">
<x-nav/>
</div>
<div class="right">
<x-search/>
<x-account v-if="os.isSignedIn"/>
<x-notifications v-if="os.isSignedIn"/>
<x-post v-if="os.isSignedIn"/>
<x-account v-if="$store.getters.isSignedIn"/>
<x-notifications v-if="$store.getters.isSignedIn"/>
<x-post v-if="$store.getters.isSignedIn"/>
<x-clock/>
</div>
</div>
@ -45,11 +45,11 @@ export default Vue.extend({
mounted() {
this.$store.commit('setUiHeaderHeight', 48);
if ((this as any).os.isSignedIn) {
const ago = (new Date().getTime() - new Date((this as any).os.i.lastUsedAt).getTime()) / 1000;
if (this.$store.getters.isSignedIn) {
const ago = (new Date().getTime() - new Date(this.$store.state.i.lastUsedAt).getTime()) / 1000;
const isHisasiburi = ago >= 3600;
(this as any).os.i.lastUsedAt = new Date();
(this as any).os.bakeMe();
this.$store.state.i.lastUsedAt = new Date();
if (isHisasiburi) {
(this.$refs.welcomeback as any).style.display = 'block';
(this.$refs.main as any).style.overflow = 'hidden';

View file

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

View file

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

View file

@ -19,7 +19,7 @@
<p>%i18n:@followers%</p><a>{{ u.followersCount }}</a>
</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>
</div>
</template>

View file

@ -3,7 +3,7 @@
<nav>
<div>
<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>
</nav>
<div class="users" v-if="!fetching && users.length != 0">

View file

@ -23,9 +23,9 @@ export default Vue.extend({
},
computed: {
withGradient(): boolean {
return (this as any).os.isSignedIn
? (this as any).clientSettings.gradientWindowHeader != null
? (this as any).clientSettings.gradientWindowHeader
return this.$store.getters.isSignedIn
? this.$store.state.settings.gradientWindowHeader != null
? this.$store.state.settings.gradientWindowHeader
: 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="body">
<header ref="header"
:class="{ withGradient: clientSettings.gradientWindowHeader }"
:class="{ withGradient: $store.state.settings.gradientWindowHeader }"
@contextmenu.prevent="() => {}" @mousedown.prevent="onHeaderMousedown"
>
<h1><slot name="header"></slot></h1>
@ -95,7 +95,7 @@ export default Vue.extend({
},
created() {
if ((this as any).os.store.state.device.autoPopout && this.popoutUrl) {
if (this.$store.state.device.autoPopout && this.popoutUrl) {
this.popout();
this.preventMount = true;
} else {

View file

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

View file

@ -63,7 +63,7 @@ export default Vue.extend({
},
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.user.bannerUrl = i.bannerUrl;

View file

@ -4,7 +4,7 @@
<div ref="left">
<x-profile :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>
</div>
</div>

View file

@ -1,6 +1,6 @@
<template>
<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"/>
<p class="followed" v-if="user.isFollowed">%i18n:@follows-you%</p>
<p class="stalk" v-if="user.isFollowing">

View file

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

View file

@ -4,16 +4,16 @@
:data-melt="props.design == 2"
>
<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%"
@click="os.apis.updateBanner"
></div>
<mk-avatar class="avatar" :user="os.i"
<mk-avatar class="avatar" :user="$store.state.i"
@click="os.apis.updateAvatar"
title="%i18n:@update-avatar%"
/>
<router-link class="name" :to="os.i | userPage">{{ os.i | userName }}</router-link>
<p class="username">@{{ os.i | acct }}</p>
<router-link class="name" :to="$store.state.i | userPage">{{ $store.state.i | userName }}</router-link>
<p class="username">@{{ $store.state.i | acct }}</p>
</div>
</template>

View file

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

View file

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

View file

@ -31,7 +31,7 @@
<div class="body">
<div class="text">
<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 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>
@ -147,7 +147,7 @@ export default Vue.extend({
// Draw map
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) {
(this as any).os.getGoogleMaps().then(maps => {
const uluru = new maps.LatLng(this.p.geo.coordinates[1], this.p.geo.coordinates[0]);

View file

@ -1,6 +1,6 @@
<template>
<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"/>
</div>
<div class="renote" v-if="isRenote">
@ -43,7 +43,7 @@
<div class="text">
<span v-if="p.isHidden" style="opacity: 0.5">(この投稿は非公開です)</span>
<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>
</div>
<div class="media" v-if="p.media.length > 0">
@ -141,7 +141,7 @@ export default Vue.extend({
},
created() {
if ((this as any).os.isSignedIn) {
if (this.$store.getters.isSignedIn) {
this.connection = (this as any).os.stream.getConnection();
this.connectionId = (this as any).os.stream.use();
}
@ -150,13 +150,13 @@ export default Vue.extend({
mounted() {
this.capture(true);
if ((this as any).os.isSignedIn) {
if (this.$store.getters.isSignedIn) {
this.connection.on('_connected_', this.onStreamConnected);
}
// Draw map
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) {
(this as any).os.getGoogleMaps().then(maps => {
const uluru = new maps.LatLng(this.p.geo.coordinates[1], this.p.geo.coordinates[0]);
@ -176,7 +176,7 @@ export default Vue.extend({
beforeDestroy() {
this.decapture(true);
if ((this as any).os.isSignedIn) {
if (this.$store.getters.isSignedIn) {
this.connection.off('_connected_', this.onStreamConnected);
(this as any).os.stream.dispose(this.connectionId);
}
@ -186,7 +186,7 @@ export default Vue.extend({
canHideText,
capture(withHandler = false) {
if ((this as any).os.isSignedIn) {
if (this.$store.getters.isSignedIn) {
this.connection.send({
type: 'capture',
id: this.p.id
@ -196,7 +196,7 @@ export default Vue.extend({
},
decapture(withHandler = false) {
if ((this as any).os.isSignedIn) {
if (this.$store.getters.isSignedIn) {
this.connection.send({
type: 'decapture',
id: this.p.id

View file

@ -121,24 +121,24 @@ export default Vue.extend({
prepend(note, silent = false) {
//#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;
if ((this as any).clientSettings.showMyRenotes === false) {
if (this.$store.state.settings.showMyRenotes === false) {
if (isMyNote && isPureRenote) {
return;
}
}
if ((this as any).clientSettings.showRenotedMyNotes === false) {
if (isPureRenote && (note.renote.userId == (this as any).os.i.id)) {
if (this.$store.state.settings.showRenotedMyNotes === false) {
if (isPureRenote && (note.renote.userId == this.$store.state.i.id)) {
return;
}
}
//#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++;
document.title = `(${this.unreadCount}) ${getNoteSummary(note)}`;
}
@ -195,7 +195,7 @@ export default Vue.extend({
this.clearNotification();
}
if ((this as any).clientSettings.fetchOnScroll !== false) {
if (this.$store.state.settings.fetchOnScroll !== false) {
// display none
// https://github.com/syuilo/misskey/issues/1569
// 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}`;
//
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;
@ -194,7 +194,7 @@ export default Vue.extend({
post() {
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', {
text: this.text == '' ? undefined : this.text,
mediaIds: this.files.length > 0 ? this.files.map(f => f.id) : undefined,

View file

@ -3,7 +3,7 @@
<div class="body">
<span v-if="note.isHidden" style="opacity: 0.5">(この投稿は非公開です)</span>
<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>
</div>
<details v-if="note.media.length > 0">

View file

@ -3,7 +3,7 @@
<mk-special-message/>
<div class="main" ref="main">
<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">
<button class="nav" @click="$parent.isDrawerOpening = true">%fa:bars%</button>
<template v-if="hasUnreadNotifications || hasUnreadMessagingMessages || hasGameInvitations">%fa:circle%</template>
@ -35,7 +35,7 @@ export default Vue.extend({
mounted() {
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.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;
(this as any).os.i.lastUsedAt = new Date();
(this as any).os.bakeMe();
this.$store.state.i.lastUsedAt = new Date();
if (isHisasiburi) {
(this.$refs.welcomeback as any).style.display = 'block';
(this.$refs.main as any).style.overflow = 'hidden';
@ -109,7 +109,7 @@ export default Vue.extend({
}
},
beforeDestroy() {
if ((this as any).os.isSignedIn) {
if (this.$store.getters.isSignedIn) {
this.connection.off('read_all_notifications', this.onReadAllNotifications);
this.connection.off('unread_notification', this.onUnreadNotification);
this.connection.off('read_all_messaging_messages', this.onReadAllMessagingMessages);

View file

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

View file

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

View file

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

View file

@ -2,7 +2,7 @@
<div class="mk-users-list">
<nav>
<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>
<div class="users" v-if="!fetching && users.length != 0">
<mk-user-preview v-for="u in users" :user="u" :key="u.id"/>

View file

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

View file

@ -87,7 +87,7 @@ export default Vue.extend({
if (this.src == 'list') {
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';
}
},

View file

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

View file

@ -17,22 +17,22 @@
</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 class="md-body-2">%i18n:@timeline%</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>
<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>
<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>
@ -52,11 +52,11 @@
<md-card-content>
<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>
<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>
@ -64,7 +64,7 @@
</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>
@ -100,11 +100,11 @@
</md-card-header>
<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>
<a :href="`${apiUrl}/connect/twitter`" target="_blank">{{ os.i.twitter ? '%i18n:@twitter-reconnect%' : '%i18n:@twitter-connect%' }}</a>
<span v-if="os.i.twitter"> or </span>
<a :href="`${apiUrl}/disconnect/twitter`" target="_blank" v-if="os.i.twitter">%i18n:@twitter-disconnect%</a>
<a :href="`${apiUrl}/connect/twitter`" target="_blank">{{ $store.state.i.twitter ? '%i18n:@twitter-reconnect%' : '%i18n:@twitter-connect%' }}</a>
<span v-if="$store.state.i.twitter"> or </span>
<a :href="`${apiUrl}/disconnect/twitter`" target="_blank" v-if="$store.state.i.twitter">%i18n:@twitter-disconnect%</a>
</p>
</md-card-content>
</md-card>
@ -156,7 +156,7 @@ export default Vue.extend({
computed: {
name(): string {
return Vue.filter('userName')((this as any).os.i);
return Vue.filter('userName')(this.$store.state.i);
},
darkmode: {

View file

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

View file

@ -11,7 +11,7 @@
<a class="avatar">
<img :src="user.avatarUrl" alt="avatar"/>
</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 class="title">
<h1>{{ user | userName }}</h1>

View file

@ -25,7 +25,7 @@
<x-friends :user="user"/>
</div>
</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>
<div>
<x-followers-you-know :user="user"/>

View file

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

View file

@ -2,13 +2,13 @@
<div class="mkw-profile">
<mk-widget-container>
<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>
<img :class="$style.avatar"
:src="`${os.i.avatarUrl}?thumbnail&size=96`"
:src="`${$store.state.i.avatarUrl}?thumbnail&size=96`"
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>
</div>
</template>

View file

@ -2,6 +2,7 @@ import Vuex from 'vuex';
import createPersistedState from 'vuex-persistedstate';
import MiOS from './mios';
import { hostname } from './config';
const defaultSettings = {
home: [],
@ -33,23 +34,29 @@ const defaultDeviceSettings = {
};
export default (os: MiOS) => new Vuex.Store({
plugins: [store => {
store.subscribe((mutation, state) => {
if (mutation.type.startsWith('settings/')) {
localStorage.setItem('settings', JSON.stringify(state.settings));
}
});
}, createPersistedState({
paths: ['device'],
filter: mut => mut.type.startsWith('device/')
plugins: [createPersistedState({
paths: ['i', 'device', 'settings']
})],
state: {
i: null,
indicate: false,
uiHeaderHeight: 0
},
getters: {
isSignedIn: state => state.i != null
},
mutations: {
updateI(state, x) {
state.i = x;
},
updateIKeyValue(state, x) {
state.i[x.key] = x.value;
},
indicate(state, 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: {
device: {
namespaced: true,
@ -134,7 +163,7 @@ export default (os: MiOS) => new Vuex.Store({
set(ctx, x) {
ctx.commit('set', x);
if (os.isSignedIn) {
if (ctx.rootGetters.isSignedIn) {
os.api('i/update_client_setting', {
name: x.key,
value: x.value