From 114a9fbdb2b3f770b8069e81aaa095602290401f Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 11 Jan 2021 22:31:17 +0900 Subject: [PATCH] =?UTF-8?q?=E3=83=86=E3=83=BC=E3=83=9E=E3=82=92=E3=83=AC?= =?UTF-8?q?=E3=82=B8=E3=82=B9=E3=83=88=E3=83=AA=E3=81=AB=E4=BF=9D=E5=AD=98?= =?UTF-8?q?=E3=81=99=E3=82=8B=E3=82=88=E3=81=86=E3=81=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/client/init.ts | 3 +- src/client/pages/settings/theme.install.vue | 8 +-- src/client/pages/settings/theme.manage.vue | 8 +-- src/client/pages/settings/theme.vue | 7 ++- src/client/store.ts | 2 +- src/client/theme-store.ts | 62 +++++++++++++++++++++ 6 files changed, 78 insertions(+), 12 deletions(-) create mode 100644 src/client/theme-store.ts diff --git a/src/client/init.ts b/src/client/init.ts index f09097fe3..554b4b332 100644 --- a/src/client/init.ts +++ b/src/client/init.ts @@ -56,6 +56,7 @@ import { defaultStore, ColdDeviceStorage } from '@/store'; import { fetchInstance, instance } from '@/instance'; import { makeHotkey } from './scripts/hotkey'; import { search } from './scripts/search'; +import { getThemes } from './theme-store'; console.info(`Misskey v${version}`); @@ -211,7 +212,7 @@ app.mount('body'); watch(defaultStore.reactiveState.darkMode, (darkMode) => { import('@/scripts/theme').then(({ builtinThemes }) => { - const themes = builtinThemes.concat(ColdDeviceStorage.get('themes')); + const themes = builtinThemes.concat(getThemes()); applyTheme(themes.find(x => x.id === (darkMode ? ColdDeviceStorage.get('darkTheme') : ColdDeviceStorage.get('lightTheme')))); }); }, { immediate: localStorage.theme == null }); diff --git a/src/client/pages/settings/theme.install.vue b/src/client/pages/settings/theme.install.vue index 407b75537..852d39f78 100644 --- a/src/client/pages/settings/theme.install.vue +++ b/src/client/pages/settings/theme.install.vue @@ -25,6 +25,7 @@ import FormButton from '@/components/form/button.vue'; import { applyTheme, validateTheme } from '@/scripts/theme'; import * as os from '@/os'; import { ColdDeviceStorage } from '@/store'; +import { addTheme, getThemes } from '@/theme-store'; export default defineComponent({ components: { @@ -74,7 +75,7 @@ export default defineComponent({ }); return false; } - if (ColdDeviceStorage.get('themes').some(t => t.id === theme.id)) { + if (getThemes().some(t => t.id === theme.id)) { os.dialog({ type: 'info', text: this.$ts._theme.alreadyInstalled @@ -90,11 +91,10 @@ export default defineComponent({ if (theme) applyTheme(theme, false); }, - install(code) { + async install(code) { const theme = this.parseThemeCode(code); if (!theme) return; - const themes = ColdDeviceStorage.get('themes').concat(theme); - ColdDeviceStorage.set('themes', themes); + await addTheme(theme); os.dialog({ type: 'success', text: this.$t('_theme.installed', { name: theme.name }) diff --git a/src/client/pages/settings/theme.manage.vue b/src/client/pages/settings/theme.manage.vue index b8126b390..5b9e07530 100644 --- a/src/client/pages/settings/theme.manage.vue +++ b/src/client/pages/settings/theme.manage.vue @@ -37,6 +37,7 @@ import { Theme, builtinThemes } from '@/scripts/theme'; import copyToClipboard from '@/scripts/copy-to-clipboard'; import * as os from '@/os'; import { ColdDeviceStorage } from '@/store'; +import { getThemes, removeTheme } from '@/theme-store'; export default defineComponent({ components: { @@ -57,7 +58,7 @@ export default defineComponent({ title: this.$ts._theme.manage, icon: faFolderOpen }, - installedThemes: ColdDeviceStorage.ref('themes'), + installedThemes: getThemes(), builtinThemes, selectedThemeId: null, faPalette, faDownload, faFolderOpen, faCheck, faTrashAlt, faEye @@ -91,10 +92,7 @@ export default defineComponent({ }, uninstall() { - const theme = this.selectedTheme; - const themes = ColdDeviceStorage.get('themes').filter(t => t.id != theme.id); - ColdDeviceStorage.set('themes', themes); - os.success(); + removeTheme(this.selectedTheme); }, } }); diff --git a/src/client/pages/settings/theme.vue b/src/client/pages/settings/theme.vue index da1ad618b..ddb525441 100644 --- a/src/client/pages/settings/theme.vue +++ b/src/client/pages/settings/theme.vue @@ -77,6 +77,7 @@ import { isDeviceDarkmode } from '@/scripts/is-device-darkmode'; import { ColdDeviceStorage } from '@/store'; import { i18n } from '@/i18n'; import { defaultStore } from '@/store'; +import { fetchThemes, getThemes } from '@/theme-store'; export default defineComponent({ components: { @@ -96,7 +97,7 @@ export default defineComponent({ icon: faPalette }; - const installedThemes = ColdDeviceStorage.ref('themes'); + const installedThemes = ref(getThemes()); const themes = computed(() => builtinThemes.concat(installedThemes.value)); const darkThemes = computed(() => themes.value.filter(t => t.base == 'dark' || t.kind == 'dark')); const lightThemes = computed(() => themes.value.filter(t => t.base == 'light' || t.kind == 'light')); @@ -137,6 +138,10 @@ export default defineComponent({ emit('info', INFO); }); + fetchThemes().then(() => { + installedThemes.value = getThemes(); + }); + return { INFO, darkThemes, diff --git a/src/client/store.ts b/src/client/store.ts index f4f609194..bf042d8ab 100644 --- a/src/client/store.ts +++ b/src/client/store.ts @@ -208,7 +208,7 @@ type Plugin = { */ export class ColdDeviceStorage { public static default = { - themes: [] as Theme[], + themes: [] as Theme[], // TODO: そのうち消す darkTheme: '8050783a-7f63-445a-b270-36d0f6ba1677', lightTheme: '4eea646f-7afa-4645-83e9-83af0333cd37', syncDeviceDarkMode: true, diff --git a/src/client/theme-store.ts b/src/client/theme-store.ts new file mode 100644 index 000000000..5e440efbf --- /dev/null +++ b/src/client/theme-store.ts @@ -0,0 +1,62 @@ +import { api } from '@/os'; +import { $i } from '@/account'; +import { ColdDeviceStorage } from './store'; +import { Theme } from './scripts/theme'; + +const lsCacheKey = $i ? `themes:${$i.id}` : ''; + +export function getThemes(): Theme[] { + return JSON.parse(localStorage.getItem(lsCacheKey) || '[]'); +} + +export async function fetchThemes(): Promise { + if ($i == null) return; + + try { + const themes = await api('i/registry/get', { scope: ['client'], key: 'themes' }); + localStorage.setItem(lsCacheKey, JSON.stringify(themes)); + } catch (e) { + if (e.code === 'NO_SUCH_KEY') return; + throw e; + } +} + +export async function addTheme(theme: Theme): Promise { + await fetchThemes(); + const themes = getThemes().concat(theme); + await api('i/registry/set', { scope: ['client'], key: 'themes', value: themes }); + localStorage.setItem(lsCacheKey, JSON.stringify(themes)); +} + +export async function removeTheme(theme: Theme): Promise { + const themes = getThemes().filter(t => t.id != theme.id); + await api('i/registry/set', { scope: ['client'], key: 'themes', value: themes }); + localStorage.setItem(lsCacheKey, JSON.stringify(themes)); +} + +// TODO: そのうち消す +if (ColdDeviceStorage.get('themes').length > 0) { + const lsThemes = ColdDeviceStorage.get('themes'); + let registryThemes; + try { + registryThemes = await api('i/registry/get', { scope: ['client'], key: 'themes' }); + } catch (e) { + if (e.code === 'NO_SUCH_KEY') { + registryThemes = []; + } else { + throw e; + } + } + const themes = [] as Theme[]; + for (const theme of lsThemes) { + if (themes.some(x => x.id === theme.id)) continue; + themes.push(theme); + } + for (const theme of registryThemes) { + if (themes.some(x => x.id === theme.id)) continue; + themes.push(theme); + } + await api('i/registry/set', { scope: ['client'], key: 'themes', value: themes }); + localStorage.setItem(lsCacheKey, JSON.stringify(themes)); + ColdDeviceStorage.set('themes', []); +}