1
0
mirror of https://github.com/misskey-dev/misskey synced 2024-11-27 22:38:39 +09:00
This commit is contained in:
syuilo 2018-05-21 02:13:39 +09:00
parent 51e3c11acb
commit 42c811a523
18 changed files with 146 additions and 136 deletions

View File

@ -495,9 +495,6 @@ desktop/views/components/settings.vue:
advanced-settings: "高度な設定"
debug-mode: "デバッグモードを有効にする"
debug-mode-desc: "この設定はブラウザに記憶されます。"
use-raw-script: "生のスクリプトを読み込む"
use-raw-script-desc: "圧縮されていない「生の」スクリプトを使用します。サイズが大きいため、読み込みに時間がかかる場合があります。この設定はブラウザに記憶されます。"
source-info: "Misskeyはソースマップも提供しています。"
experimental: "実験的機能を有効にする"
experimental-desc: "実験的機能を有効にするとMisskeyの動作が不安定になる可能性があります。この設定はブラウザに記憶されます。"
tools: "ツール"

View File

@ -211,6 +211,7 @@
"vue-template-compiler": "2.5.16",
"vuedraggable": "2.16.0",
"vuex": "3.0.1",
"vuex-persistedstate": "^2.5.4",
"web-push": "3.3.1",
"webfinger.js": "2.6.6",
"webpack": "4.8.3",

View File

@ -29,11 +29,21 @@
if (url.pathname == '/auth') app = 'auth';
//#endregion
// Detect the user language
// Note: The default language is Japanese
//#region Detect the user language
let lang = navigator.language.split('-')[0];
// The default language is English
if (!LANGS.includes(lang)) lang = 'en';
if (localStorage.getItem('lang')) lang = localStorage.getItem('lang');
const vuex = localStorage.getItem('vuex');
if (vuex) {
const data = JSON.parse(vuex);
if (data.device.lang) lang = data.device.lang;
}
const storedLang = localStorage.getItem('lang');
if (storedLang) lang = storedLang;
//#endregion
// Detect the user agent
const ua = navigator.userAgent.toLowerCase();
@ -68,13 +78,6 @@
// Script version
const ver = localStorage.getItem('v') || VERSION;
// Whether in debug mode
const isDebug = localStorage.getItem('debug') == 'true';
// Whether use raw version script
const raw = (localStorage.getItem('useRawScript') == 'true' && isDebug)
|| ENV != 'production';
// Get salt query
const salt = localStorage.getItem('salt')
? '?salt=' + localStorage.getItem('salt')
@ -84,7 +87,7 @@
// Note: 'async' make it possible to load the script asyncly.
// 'defer' make it possible to run the script when the dom loaded.
const script = document.createElement('script');
script.setAttribute('src', `/assets/${app}.${ver}.${lang}.${raw ? 'raw' : 'min'}.js${salt}`);
script.setAttribute('src', `/assets/${app}.${ver}.${lang}.js${salt}`);
script.setAttribute('async', 'true');
script.setAttribute('defer', 'true');
head.appendChild(script);

View File

@ -22,7 +22,7 @@ export default Vue.extend({
},
computed: {
lightmode(): boolean {
return localStorage.getItem('lightmode') == 'true';
return this.$store.state.device.lightmode;
},
style(): any {
return {

View File

@ -149,9 +149,9 @@ export default Vue.extend({
onMessage(message) {
//
if ((this as any).os.isEnableSounds) {
if (this.$store.state.device.enableSounds) {
const sound = new Audio(`${url}/assets/message.mp3`);
sound.volume = localStorage.getItem('soundVolume') ? parseInt(localStorage.getItem('soundVolume'), 10) / 100 : 0.5;
sound.volume = this.$store.state.device.soundVolume;
sound.play();
}

View File

@ -162,9 +162,9 @@ export default Vue.extend({
this.o.put(this.myColor, pos);
//
if ((this as any).os.isEnableSounds) {
if (this.$store.state.device.enableSounds) {
const sound = new Audio(`${url}/assets/othello-put-me.mp3`);
sound.volume = localStorage.getItem('soundVolume') ? parseInt(localStorage.getItem('soundVolume'), 10) / 100 : 0.5;
sound.volume = this.$store.state.device.soundVolume;
sound.play();
}
@ -186,9 +186,9 @@ export default Vue.extend({
this.$forceUpdate();
//
if ((this as any).os.isEnableSounds && x.color != this.myColor) {
if (this.$store.state.device.enableSounds && x.color != this.myColor) {
const sound = new Audio(`${url}/assets/othello-put-you.mp3`);
sound.volume = localStorage.getItem('soundVolume') ? parseInt(localStorage.getItem('soundVolume'), 10) / 100 : 0.5;
sound.volume = this.$store.state.device.soundVolume;
sound.play();
}
},

View File

@ -8,6 +8,7 @@ declare const _STATS_URL_: string;
declare const _STATUS_URL_: string;
declare const _DEV_URL_: string;
declare const _LANG_: string;
declare const _LANGS_: string;
declare const _RECAPTCHA_SITEKEY_: string;
declare const _SW_PUBLICKEY_: string;
declare const _THEME_COLOR_: string;
@ -27,6 +28,7 @@ export const statsUrl = _STATS_URL_;
export const statusUrl = _STATUS_URL_;
export const devUrl = _DEV_URL_;
export const lang = _LANG_;
export const langs = _LANGS_;
export const recaptchaSitekey = _RECAPTCHA_SITEKEY_;
export const swPublickey = _SW_PUBLICKEY_;
export const themeColor = _THEME_COLOR_;

View File

@ -102,7 +102,7 @@ export default Vue.extend({
computed: {
home(): any[] {
return this.$store.state.settings.data.home;
return this.$store.state.settings.home;
},
left(): any[] {
return this.home.filter(w => w.place == 'left');

View File

@ -145,9 +145,9 @@ export default Vue.extend({
this.notes.unshift(note);
//
if ((this as any).os.isEnableSounds && !silent) {
if (this.$store.state.device.enableSounds && !silent) {
const sound = new Audio(`${url}/assets/post.mp3`);
sound.volume = localStorage.getItem('soundVolume') ? parseInt(localStorage.getItem('soundVolume'), 10) / 100 : 0.5;
sound.volume = this.$store.state.device.soundVolume;
sound.play();
}

View File

@ -62,8 +62,10 @@
<el-slider
v-model="soundVolume"
:show-input="true"
:format-tooltip="v => `${v}%`"
:format-tooltip="v => `${v * 100}%`"
:disabled="!enableSounds"
:max="1"
:step="0.1"
/>
<button class="ui button" @click="soundTest">%fa:volume-up% %i18n:@test%</button>
</section>
@ -77,14 +79,10 @@
<h1>%i18n:@language%</h1>
<el-select v-model="lang" placeholder="%i18n:@pick-language%">
<el-option-group label="%i18n:@recommended%">
<el-option label="%i18n:@auto%" value=""/>
<el-option label="%i18n:@auto%" :value="null"/>
</el-option-group>
<el-option-group label="%i18n:@specify-language%">
<el-option label="日本語" value="ja"/>
<el-option label="English" value="en"/>
<el-option label="Français" value="fr"/>
<el-option label="Polski" value="pl"/>
<el-option label="Deutsch" value="de"/>
<el-option v-for="x in langs" :label="x[1]" :value="x[0]" :key="x[0]"/>
</el-option-group>
</el-select>
<div class="none ui info">
@ -178,15 +176,7 @@
<mk-switch v-model="debug" text="%i18n:@debug-mode%">
<span>%i18n:@debug-mode-desc%</span>
</mk-switch>
<template v-if="debug">
<mk-switch v-model="useRawScript" text="%i18n:@use-raw-script%">
<span>%i18n:@use-raw-script-desc%</span>
</mk-switch>
<div class="none ui info">
<p>%fa:info-circle%%i18n:@source-info%</p>
</div>
</template>
<mk-switch v-model="enableExperimental" text="%i18n:@experimental%">
<mk-switch v-model="enableExperimentalFeatures" text="%i18n:@experimental%">
<span>%i18n:@experimental-desc%</span>
</mk-switch>
<details v-if="debug">
@ -214,7 +204,7 @@ import XApi from './settings.api.vue';
import XApps from './settings.apps.vue';
import XSignins from './settings.signins.vue';
import XDrive from './settings.drive.vue';
import { url, docsUrl, license, lang, version } from '../../../config';
import { url, docsUrl, license, lang, langs, version } from '../../../config';
import checkForUpdate from '../../../common/scripts/check-for-update';
import MkTaskManager from './taskmanager.vue';
@ -235,55 +225,60 @@ export default Vue.extend({
meta: null,
license,
version,
langs,
latestVersion: undefined,
checkingForUpdate: false,
darkmode: localStorage.getItem('darkmode') == 'true',
enableSounds: localStorage.getItem('enableSounds') == 'true',
autoPopout: localStorage.getItem('autoPopout') == 'true',
apiViaStream: localStorage.getItem('apiViaStream') ? localStorage.getItem('apiViaStream') == 'true' : true,
soundVolume: localStorage.getItem('soundVolume') ? parseInt(localStorage.getItem('soundVolume'), 10) : 50,
lang: localStorage.getItem('lang') || '',
preventUpdate: localStorage.getItem('preventUpdate') == 'true',
debug: localStorage.getItem('debug') == 'true',
useRawScript: localStorage.getItem('useRawScript') == 'true',
enableExperimental: localStorage.getItem('enableExperimental') == 'true'
darkmode: localStorage.getItem('darkmode') == 'true'
};
},
computed: {
licenseUrl(): string {
return `${docsUrl}/${lang}/license`;
},
apiViaStream: {
get() { return this.$store.state.device.apiViaStream; },
set(value) { this.$store.commit('device/set', { key: 'apiViaStream', value }); }
},
autoPopout: {
get() { return this.$store.state.device.autoPopout; },
set(value) { this.$store.commit('device/set', { key: 'autoPopout', value }); }
},
enableSounds: {
get() { return this.$store.state.device.enableSounds; },
set(value) { this.$store.commit('device/set', { key: 'enableSounds', value }); }
},
soundVolume: {
get() { return this.$store.state.device.soundVolume; },
set(value) { this.$store.commit('device/set', { key: 'soundVolume', value }); }
},
lang: {
get() { return this.$store.state.device.lang; },
set(value) { this.$store.commit('device/set', { key: 'lang', value }); }
},
preventUpdate: {
get() { return this.$store.state.device.preventUpdate; },
set(value) { this.$store.commit('device/set', { key: 'preventUpdate', value }); }
},
debug: {
get() { return this.$store.state.device.debug; },
set(value) { this.$store.commit('device/set', { key: 'debug', value }); }
},
enableExperimentalFeatures: {
get() { return this.$store.state.device.enableExperimentalFeatures; },
set(value) { this.$store.commit('device/set', { key: 'enableExperimentalFeatures', value }); }
}
},
watch: {
autoPopout() {
localStorage.setItem('autoPopout', this.autoPopout ? 'true' : 'false');
},
apiViaStream() {
localStorage.setItem('apiViaStream', this.apiViaStream ? 'true' : 'false');
},
darkmode() {
(this as any)._updateDarkmode_(this.darkmode);
},
enableSounds() {
localStorage.setItem('enableSounds', this.enableSounds ? 'true' : 'false');
},
soundVolume() {
localStorage.setItem('soundVolume', this.soundVolume.toString());
},
lang() {
localStorage.setItem('lang', this.lang);
},
preventUpdate() {
localStorage.setItem('preventUpdate', this.preventUpdate ? 'true' : 'false');
},
debug() {
localStorage.setItem('debug', this.debug ? 'true' : 'false');
},
useRawScript() {
localStorage.setItem('useRawScript', this.useRawScript ? 'true' : 'false');
},
enableExperimental() {
localStorage.setItem('enableExperimental', this.enableExperimental ? 'true' : 'false');
}
},
created() {
@ -391,7 +386,7 @@ export default Vue.extend({
},
soundTest() {
const sound = new Audio(`${url}/assets/message.mp3`);
sound.volume = localStorage.getItem('soundVolume') ? parseInt(localStorage.getItem('soundVolume'), 10) / 100 : 0.5;
sound.volume = this.$store.state.device.soundVolume;
sound.play();
}
}

View File

@ -95,7 +95,7 @@ export default Vue.extend({
},
created() {
if (localStorage.getItem('autoPopout') == 'true' && this.popoutUrl) {
if (this.$store.state.device.autoPopout && this.popoutUrl) {
this.popout();
this.preventMount = true;
} else {

View File

@ -147,7 +147,7 @@ export default (callback: (launch: (router: VueRouter, api?: (os: MiOS) => API)
os,
api: os.api,
apis: os.apis,
clientSettings: os.store.state.settings.data
clientSettings: os.store.state.settings
};
}
});
@ -173,7 +173,7 @@ export default (callback: (launch: (router: VueRouter, api?: (os: MiOS) => API)
}
//#region 更新チェック
const preventUpdate = localStorage.getItem('preventUpdate') == 'true';
const preventUpdate = os.store.state.device.preventUpdate;
if (!preventUpdate) {
setTimeout(() => {
checkForUpdate(os);

View File

@ -98,14 +98,7 @@ export default class MiOS extends EventEmitter {
* Whether is debug mode
*/
public get debug() {
return localStorage.getItem('debug') == 'true';
}
/**
* Whether enable sounds
*/
public get isEnableSounds() {
return localStorage.getItem('enableSounds') == 'true';
return this.store ? this.store.state.device.debug : false;
}
public store: ReturnType<typeof initStore>;
@ -435,12 +428,8 @@ export default class MiOS extends EventEmitter {
});
});
// Whether use raw version script
const raw = (localStorage.getItem('useRawScript') == 'true' && this.debug)
|| process.env.NODE_ENV != 'production';
// The path of service worker script
const sw = `/sw.${version}.${lang}.${raw ? 'raw' : 'min'}.js`;
const sw = `/sw.${version}.${lang}.js`;
// Register service worker
navigator.serviceWorker.register(sw).then(registration => {
@ -471,8 +460,7 @@ export default class MiOS extends EventEmitter {
};
const promise = new Promise((resolve, reject) => {
const viaStream = this.stream && this.stream.hasConnection &&
(localStorage.getItem('apiViaStream') ? localStorage.getItem('apiViaStream') == 'true' : true);
const viaStream = this.stream && this.stream.hasConnection && this.store.state.device.apiViaStream;
if (viaStream) {
const stream = this.stream.borrow();

View File

@ -17,7 +17,7 @@ export default Vue.extend({
},
computed: {
lightmode(): boolean {
return localStorage.getItem('lightmode') == 'true';
return this.$store.state.device.lightmode;
},
style(): any {
return {

View File

@ -71,11 +71,7 @@
</md-optgroup>
<md-optgroup label="%i18n:@specify-language%">
<md-option value="ja">日本語</md-option>
<md-option value="en">English</md-option>
<md-option value="fr">Français</md-option>
<md-option value="pl">Polski</md-option>
<md-option value="de">Deutsch</md-option>
<md-option v-for="x in langs" :value="x[0]" :key="x[0]">{{ x[1] }}</md-option>
</md-optgroup>
</md-select>
</md-field>
@ -122,7 +118,7 @@
<script lang="ts">
import Vue from 'vue';
import { apiUrl, version, codename } from '../../../config';
import { apiUrl, version, codename, langs } from '../../../config';
import checkForUpdate from '../../../common/scripts/check-for-update';
import XProfile from './settings/settings.profile.vue';
@ -137,9 +133,8 @@ export default Vue.extend({
apiUrl,
version,
codename,
langs,
darkmode: localStorage.getItem('darkmode') == 'true',
lightmode: localStorage.getItem('lightmode') == 'true',
lang: localStorage.getItem('lang') || '',
latestVersion: undefined,
checkingForUpdate: false
};
@ -148,20 +143,22 @@ export default Vue.extend({
computed: {
name(): string {
return Vue.filter('userName')((this as any).os.i);
}
},
lightmode: {
get() { return this.$store.state.device.lightmode; },
set(value) { this.$store.commit('device/set', { key: 'lightmode', value }); }
},
lang: {
get() { return this.$store.state.device.lang; },
set(value) { this.$store.commit('device/set', { key: 'lang', value }); }
},
},
watch: {
darkmode() {
(this as any)._updateDarkmode_(this.darkmode);
},
lightmode() {
localStorage.setItem('lightmode', this.lightmode);
},
lang() {
localStorage.setItem('lang', this.lang);
}
},

View File

@ -65,7 +65,7 @@ export default Vue.extend({
computed: {
widgets(): any[] {
return this.$store.state.settings.data.mobileHome;
return this.$store.state.settings.mobileHome;
}
},

View File

@ -1,4 +1,6 @@
import Vuex from 'vuex';
import createPersistedState from 'vuex-persistedstate';
import MiOS from './mios';
const defaultSettings = {
@ -14,14 +16,28 @@ const defaultSettings = {
showRenotedMyNotes: true
};
const defaultDeviceSettings = {
apiViaStream: true,
autoPopout: false,
enableSounds: true,
soundVolume: 0.5,
lang: null,
preventUpdate: false,
debug: false,
lightmode: false,
};
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.data));
localStorage.setItem('settings', JSON.stringify(state.settings));
}
});
}],
}, createPersistedState({
paths: ['device'],
filter: mut => mut.type.startsWith('device/')
})],
state: {
indicate: false,
@ -39,50 +55,60 @@ export default (os: MiOS) => new Vuex.Store({
},
modules: {
settings: {
device: {
namespaced: true,
state: {
data: defaultSettings
},
state: defaultDeviceSettings,
mutations: {
set(state, x: { key: string; value: any }) {
state.data[x.key] = x.value;
state[x.key] = x.value;
}
}
},
settings: {
namespaced: true,
state: defaultSettings,
mutations: {
set(state, x: { key: string; value: any }) {
state[x.key] = x.value;
},
setHome(state, data) {
state.data.home = data;
state.home = data;
},
setHomeWidget(state, x) {
const w = state.data.home.find(w => w.id == x.id);
const w = state.home.find(w => w.id == x.id);
if (w) {
w.data = x.data;
}
},
addHomeWidget(state, widget) {
state.data.home.unshift(widget);
state.home.unshift(widget);
},
setMobileHome(state, data) {
state.data.mobileHome = data;
state.mobileHome = data;
},
setMobileHomeWidget(state, x) {
const w = state.data.mobileHome.find(w => w.id == x.id);
const w = state.mobileHome.find(w => w.id == x.id);
if (w) {
w.data = x.data;
}
},
addMobileHomeWidget(state, widget) {
state.data.mobileHome.unshift(widget);
state.mobileHome.unshift(widget);
},
removeMobileHomeWidget(state, widget) {
state.data.mobileHome = state.data.mobileHome.filter(w => w.id != widget.id);
state.mobileHome = state.mobileHome.filter(w => w.id != widget.id);
}
},
@ -108,7 +134,7 @@ export default (os: MiOS) => new Vuex.Store({
ctx.commit('addHomeWidget', widget);
os.api('i/update_home', {
home: ctx.state.data.home
home: ctx.state.home
});
},
@ -116,7 +142,7 @@ export default (os: MiOS) => new Vuex.Store({
ctx.commit('addMobileHomeWidget', widget);
os.api('i/update_mobile_home', {
home: ctx.state.data.mobileHome
home: ctx.state.mobileHome
});
},
@ -124,7 +150,7 @@ export default (os: MiOS) => new Vuex.Store({
ctx.commit('removeMobileHomeWidget', widget);
os.api('i/update_mobile_home', {
home: ctx.state.data.mobileHome.filter(w => w.id != widget.id)
home: ctx.state.mobileHome.filter(w => w.id != widget.id)
});
}
}

View File

@ -60,7 +60,7 @@ const entry = {
const output = {
path: __dirname + '/built/client/assets',
filename: `[name].${version}.-.${isProduction ? 'min' : 'raw'}.js`
filename: `[name].${version}.-.js`
};
//#region Define consts
@ -78,6 +78,7 @@ const consts = {
_WS_URL_: config.ws_url,
_DEV_URL_: config.dev_url,
_LANG_: '%lang%',
_LANGS_: Object.keys(locales).map(l => [l, locales[l].meta.lang]),
_HOST_: config.host,
_HOSTNAME_: config.hostname,
_URL_: config.url,
@ -110,14 +111,14 @@ const plugins = [
//#region i18n
langs.forEach(lang => {
Object.keys(entry).forEach(file => {
let src = fs.readFileSync(`${__dirname}/built/client/assets/${file}.${version}.-.${isProduction ? 'min' : 'raw'}.js`, 'utf-8');
let src = fs.readFileSync(`${__dirname}/built/client/assets/${file}.${version}.-.js`, 'utf-8');
const i18nReplacer = new I18nReplacer(lang);
src = src.replace(i18nReplacer.pattern, i18nReplacer.replacement);
src = src.replace('%lang%', lang);
fs.writeFileSync(`${__dirname}/built/client/assets/${file}.${version}.${lang}.${isProduction ? 'min' : 'raw'}.js`, src, 'utf-8');
fs.writeFileSync(`${__dirname}/built/client/assets/${file}.${version}.${lang}.js`, src, 'utf-8');
});
});
//#endregion