/* * SPDX-FileCopyrightText: syuilo and misskey-project * SPDX-License-Identifier: AGPL-3.0-only */ import { ref, watch } from 'vue'; import type { PreferencesProfile } from './profile.js'; import type { MenuItem } from '@/types/menu.js'; import { copyToClipboard } from '@/scripts/copy-to-clipboard.js'; import { i18n } from '@/i18n.js'; import { miLocalStorage } from '@/local-storage.js'; import { prefer, profileManager } from '@/preferences.js'; import * as os from '@/os.js'; import { store } from '@/store.js'; import { $i } from '@/account.js'; import { misskeyApi } from '@/scripts/misskey-api.js'; import { unisonReload } from '@/scripts/unison-reload.js'; function canAutoBackup() { return profileManager.profile.name != null && profileManager.profile.name.trim() !== ''; } export function getPreferencesProfileMenu(): MenuItem[] { const autoBackupEnabled = ref(store.state.enablePreferencesAutoCloudBackup); watch(autoBackupEnabled, () => { if (autoBackupEnabled.value) { if (!canAutoBackup()) { autoBackupEnabled.value = false; os.alert({ type: 'warning', title: i18n.ts._preferencesBackup.youNeedToNameYourProfileToEnableAutoBackup, }); return; } store.set('enablePreferencesAutoCloudBackup', true); } else { store.set('enablePreferencesAutoCloudBackup', false); } }); const menu: MenuItem[] = [{ type: 'label', text: profileManager.profile.name || `(${i18n.ts.noName})`, }, { text: i18n.ts.rename, icon: 'ti ti-pencil', action: () => { renameProfile(); }, }, { type: 'switch', icon: 'ti ti-cloud-up', text: i18n.ts._preferencesBackup.autoBackup, ref: autoBackupEnabled, }, { text: i18n.ts.export, icon: 'ti ti-download', action: () => { exportCurrentProfile(); }, }, { type: 'divider', }, { text: i18n.ts._preferencesBackup.restoreFromBackup, icon: 'ti ti-cloud-down', action: () => { restoreFromCloudBackup(); }, }, { text: i18n.ts.import, icon: 'ti ti-upload', action: () => { importProfile(); }, }]; if (prefer.s.devMode) { menu.push({ type: 'divider', }, { text: 'Copy profile as text', icon: 'ti ti-clipboard', action: () => { copyToClipboard(JSON.stringify(profileManager.profile, null, '\t')); }, }); } return menu; } async function renameProfile() { const { canceled, result: name } = await os.inputText({ title: i18n.ts._preferencesProfile.profileName, text: i18n.ts._preferencesProfile.profileNameDescription + '\n' + i18n.ts._preferencesProfile.profileNameDescription2, placeholder: profileManager.profile.name || null, default: profileManager.profile.name || null, }); if (canceled || name == null || name.trim() === '') return; profileManager.renameProfile(name); } function exportCurrentProfile() { const p = profileManager.profile; const txtBlob = new Blob([JSON.stringify(p)], { type: 'text/plain' }); const dummya = document.createElement('a'); dummya.href = URL.createObjectURL(txtBlob); dummya.download = `${p.name || p.id}.misskeypreferences`; dummya.click(); } function importProfile() { const input = document.createElement('input'); input.type = 'file'; input.accept = '.misskeypreferences'; input.onchange = async () => { if (input.files == null || input.files.length === 0) return; const file = input.files[0]; const txt = await file.text(); const profile = JSON.parse(txt) as PreferencesProfile; miLocalStorage.setItem('preferences', JSON.stringify(profile)); miLocalStorage.setItem('hidePreferencesRestoreSuggestion', 'true'); shouldSuggestRestoreBackup.value = false; unisonReload(); }; input.click(); } export async function cloudBackup() { if ($i == null) return; if (!canAutoBackup()) { throw new Error('Profile name is not set'); } await misskeyApi('i/registry/set', { scope: ['client', 'preferences', 'backups'], key: profileManager.profile.name, value: profileManager.profile, }); } export async function restoreFromCloudBackup() { if ($i == null) return; // TODO: 更新日時でソートして取得したい const keys = await misskeyApi('i/registry/keys', { scope: ['client', 'preferences', 'backups'], }); console.log(keys); if (keys.length === 0) { os.alert({ type: 'warning', title: i18n.ts._preferencesBackup.noBackupsFoundTitle, text: i18n.ts._preferencesBackup.noBackupsFoundDescription, }); return; } const select = await os.select({ title: i18n.ts._preferencesBackup.selectBackupToRestore, items: keys.map(k => ({ text: k, value: k, })), }); if (select.canceled) return; if (select.result == null) return; const profile = await misskeyApi('i/registry/get', { scope: ['client', 'preferences', 'backups'], key: select.result, }); console.log(profile); miLocalStorage.setItem('preferences', JSON.stringify(profile)); miLocalStorage.setItem('hidePreferencesRestoreSuggestion', 'true'); store.set('enablePreferencesAutoCloudBackup', true); shouldSuggestRestoreBackup.value = false; unisonReload(); } export async function enableAutoBackup() { if (!canAutoBackup()) { await renameProfile(); } if (!canAutoBackup()) { return; } store.set('enablePreferencesAutoCloudBackup', true); } export const shouldSuggestRestoreBackup = ref(false); if ($i != null) { if (new Date($i.createdAt).getTime() < (Date.now() - 1000 * 60 * 30)) { // アカウント作成直後は意味ないので除外 miLocalStorage.setItem('hidePreferencesRestoreSuggestion', 'true'); } else { if (miLocalStorage.getItem('hidePreferencesRestoreSuggestion') !== 'true') { misskeyApi('i/registry/keys', { scope: ['client', 'preferences', 'backups'], }).then(keys => { if (keys.length === 0) { miLocalStorage.setItem('hidePreferencesRestoreSuggestion', 'true'); } else { shouldSuggestRestoreBackup.value = true; } }); } } } export function hideRestoreBackupSuggestion() { miLocalStorage.setItem('hidePreferencesRestoreSuggestion', 'true'); shouldSuggestRestoreBackup.value = false; }