Merge branch 'develop' into pag-back
This commit is contained in:
commit
848b72ae21
1 changed files with 28 additions and 37 deletions
|
@ -32,7 +32,7 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, onMounted, onUnmounted } from 'vue';
|
import { computed, onMounted, onUnmounted, ref } from 'vue';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import FormSection from '@/components/form/section.vue';
|
import FormSection from '@/components/form/section.vue';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
|
@ -94,15 +94,6 @@ const coldDeviceStorageSaveKeys: (keyof typeof ColdDeviceStorage.default)[] = [
|
||||||
'darkTheme',
|
'darkTheme',
|
||||||
'syncDeviceDarkMode',
|
'syncDeviceDarkMode',
|
||||||
'plugins',
|
'plugins',
|
||||||
'mediaVolume',
|
|
||||||
'sound_masterVolume',
|
|
||||||
'sound_note',
|
|
||||||
'sound_noteMy',
|
|
||||||
'sound_notification',
|
|
||||||
'sound_chat',
|
|
||||||
'sound_chatBg',
|
|
||||||
'sound_antenna',
|
|
||||||
'sound_channel',
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const scope = ['clientPreferencesProfiles'];
|
const scope = ['clientPreferencesProfiles'];
|
||||||
|
@ -126,18 +117,18 @@ type Profile = {
|
||||||
|
|
||||||
const connection = $i && useStream().useChannel('main');
|
const connection = $i && useStream().useChannel('main');
|
||||||
|
|
||||||
let profiles = $ref<Record<string, Profile> | null>(null);
|
const profiles = ref<Record<string, Profile> | null>(null);
|
||||||
|
|
||||||
os.api('i/registry/get-all', { scope })
|
os.api('i/registry/get-all', { scope })
|
||||||
.then(res => {
|
.then(res => {
|
||||||
profiles = res || {};
|
profiles.value = res || {};
|
||||||
});
|
});
|
||||||
|
|
||||||
function isObject(value: unknown): value is Record<string, unknown> {
|
function isObject(value: unknown): value is Record<string, unknown> {
|
||||||
return value != null && typeof value === 'object' && !Array.isArray(value);
|
return value != null && typeof value === 'object' && !Array.isArray(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
function validate(profile: unknown): void {
|
function validate(profile: any): void {
|
||||||
if (!isObject(profile)) throw new Error('not an object');
|
if (!isObject(profile)) throw new Error('not an object');
|
||||||
|
|
||||||
// Check if unnecessary properties exist
|
// Check if unnecessary properties exist
|
||||||
|
@ -148,9 +139,9 @@ function validate(profile: unknown): void {
|
||||||
|
|
||||||
// Check if createdAt and updatedAt is Date
|
// Check if createdAt and updatedAt is Date
|
||||||
// https://zenn.dev/lollipop_onl/articles/eoz-judge-js-invalid-date
|
// https://zenn.dev/lollipop_onl/articles/eoz-judge-js-invalid-date
|
||||||
if (!profile.createdAt || Number.isNaN(new Date(profile.createdAt).getTime())) throw new Error('createdAt is falsy or not Date');
|
if (!profile.createdAt || Number.isNaN(new Date(profile.createdAt as any).getTime())) throw new Error('createdAt is falsy or not Date');
|
||||||
if (profile.updatedAt) {
|
if (profile.updatedAt) {
|
||||||
if (Number.isNaN(new Date(profile.updatedAt).getTime())) {
|
if (Number.isNaN(new Date(profile.updatedAt as any).getTime())) {
|
||||||
throw new Error('updatedAt is not Date');
|
throw new Error('updatedAt is not Date');
|
||||||
}
|
}
|
||||||
} else if (profile.updatedAt !== null) {
|
} else if (profile.updatedAt !== null) {
|
||||||
|
@ -182,14 +173,14 @@ function getSettings(): Profile['settings'] {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function saveNew(): Promise<void> {
|
async function saveNew(): Promise<void> {
|
||||||
if (!profiles) return;
|
if (!profiles.value) return;
|
||||||
|
|
||||||
const { canceled, result: name } = await os.inputText({
|
const { canceled, result: name } = await os.inputText({
|
||||||
title: ts._preferencesBackups.inputName,
|
title: ts._preferencesBackups.inputName,
|
||||||
});
|
});
|
||||||
if (canceled) return;
|
if (canceled) return;
|
||||||
|
|
||||||
if (Object.values(profiles).some(x => x.name === name)) {
|
if (Object.values(profiles.value).some(x => x.name === name)) {
|
||||||
return os.alert({
|
return os.alert({
|
||||||
title: ts._preferencesBackups.cannotSave,
|
title: ts._preferencesBackups.cannotSave,
|
||||||
text: t('_preferencesBackups.nameAlreadyExists', { name }),
|
text: t('_preferencesBackups.nameAlreadyExists', { name }),
|
||||||
|
@ -213,7 +204,7 @@ function loadFile(): void {
|
||||||
input.type = 'file';
|
input.type = 'file';
|
||||||
input.multiple = false;
|
input.multiple = false;
|
||||||
input.onchange = async () => {
|
input.onchange = async () => {
|
||||||
if (!profiles) return;
|
if (!profiles.value) return;
|
||||||
if (!input.files || input.files.length === 0) return;
|
if (!input.files || input.files.length === 0) return;
|
||||||
|
|
||||||
const file = input.files[0];
|
const file = input.files[0];
|
||||||
|
@ -234,7 +225,7 @@ function loadFile(): void {
|
||||||
return os.alert({
|
return os.alert({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
title: ts._preferencesBackups.cannotLoad,
|
title: ts._preferencesBackups.cannotLoad,
|
||||||
text: err?.message,
|
text: (err as any)?.message ?? '',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,9 +244,9 @@ function loadFile(): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function applyProfile(id: string): Promise<void> {
|
async function applyProfile(id: string): Promise<void> {
|
||||||
if (!profiles) return;
|
if (!profiles.value) return;
|
||||||
|
|
||||||
const profile = profiles[id];
|
const profile = profiles.value[id];
|
||||||
|
|
||||||
const { canceled: cancel1 } = await os.confirm({
|
const { canceled: cancel1 } = await os.confirm({
|
||||||
type: 'warning',
|
type: 'warning',
|
||||||
|
@ -313,23 +304,23 @@ async function applyProfile(id: string): Promise<void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function deleteProfile(id: string): Promise<void> {
|
async function deleteProfile(id: string): Promise<void> {
|
||||||
if (!profiles) return;
|
if (!profiles.value) return;
|
||||||
|
|
||||||
const { canceled } = await os.confirm({
|
const { canceled } = await os.confirm({
|
||||||
type: 'info',
|
type: 'info',
|
||||||
title: ts.delete,
|
title: ts.delete,
|
||||||
text: t('deleteAreYouSure', { x: profiles[id].name }),
|
text: t('deleteAreYouSure', { x: profiles.value[id].name }),
|
||||||
});
|
});
|
||||||
if (canceled) return;
|
if (canceled) return;
|
||||||
|
|
||||||
await os.apiWithDialog('i/registry/remove', { scope, key: id });
|
await os.apiWithDialog('i/registry/remove', { scope, key: id });
|
||||||
delete profiles[id];
|
delete profiles.value[id];
|
||||||
}
|
}
|
||||||
|
|
||||||
async function save(id: string): Promise<void> {
|
async function save(id: string): Promise<void> {
|
||||||
if (!profiles) return;
|
if (!profiles.value) return;
|
||||||
|
|
||||||
const { name, createdAt } = profiles[id];
|
const { name, createdAt } = profiles.value[id];
|
||||||
|
|
||||||
const { canceled } = await os.confirm({
|
const { canceled } = await os.confirm({
|
||||||
type: 'info',
|
type: 'info',
|
||||||
|
@ -350,25 +341,25 @@ async function save(id: string): Promise<void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function rename(id: string): Promise<void> {
|
async function rename(id: string): Promise<void> {
|
||||||
if (!profiles) return;
|
if (!profiles.value) return;
|
||||||
|
|
||||||
const { canceled: cancel1, result: name } = await os.inputText({
|
const { canceled: cancel1, result: name } = await os.inputText({
|
||||||
title: ts._preferencesBackups.inputName,
|
title: ts._preferencesBackups.inputName,
|
||||||
});
|
});
|
||||||
if (cancel1 || profiles[id].name === name) return;
|
if (cancel1 || profiles.value[id].name === name) return;
|
||||||
|
|
||||||
if (Object.values(profiles).some(x => x.name === name)) {
|
if (Object.values(profiles.value).some(x => x.name === name)) {
|
||||||
return os.alert({
|
return os.alert({
|
||||||
title: ts._preferencesBackups.cannotSave,
|
title: ts._preferencesBackups.cannotSave,
|
||||||
text: t('_preferencesBackups.nameAlreadyExists', { name }),
|
text: t('_preferencesBackups.nameAlreadyExists', { name }),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const registry = Object.assign({}, { ...profiles[id] });
|
const registry = Object.assign({}, { ...profiles.value[id] });
|
||||||
|
|
||||||
const { canceled: cancel2 } = await os.confirm({
|
const { canceled: cancel2 } = await os.confirm({
|
||||||
type: 'info',
|
type: 'info',
|
||||||
title: ts._preferencesBackups.rename,
|
title: ts.rename,
|
||||||
text: t('_preferencesBackups.renameConfirm', { old: registry.name, new: name }),
|
text: t('_preferencesBackups.renameConfirm', { old: registry.name, new: name }),
|
||||||
});
|
});
|
||||||
if (cancel2) return;
|
if (cancel2) return;
|
||||||
|
@ -378,7 +369,7 @@ async function rename(id: string): Promise<void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
function menu(ev: MouseEvent, profileId: string) {
|
function menu(ev: MouseEvent, profileId: string) {
|
||||||
if (!profiles) return;
|
if (!profiles.value) return;
|
||||||
|
|
||||||
return os.popupMenu([{
|
return os.popupMenu([{
|
||||||
text: ts._preferencesBackups.apply,
|
text: ts._preferencesBackups.apply,
|
||||||
|
@ -388,8 +379,8 @@ function menu(ev: MouseEvent, profileId: string) {
|
||||||
type: 'a',
|
type: 'a',
|
||||||
text: ts.download,
|
text: ts.download,
|
||||||
icon: 'ti ti-download',
|
icon: 'ti ti-download',
|
||||||
href: URL.createObjectURL(new Blob([JSON.stringify(profiles[profileId], null, 2)], { type: 'application/json' })),
|
href: URL.createObjectURL(new Blob([JSON.stringify(profiles.value[profileId], null, 2)], { type: 'application/json' })),
|
||||||
download: `${profiles[profileId].name}.json`,
|
download: `${profiles.value[profileId].name}.json`,
|
||||||
}, null, {
|
}, null, {
|
||||||
text: ts.rename,
|
text: ts.rename,
|
||||||
icon: 'ti ti-forms',
|
icon: 'ti ti-forms',
|
||||||
|
@ -403,16 +394,16 @@ function menu(ev: MouseEvent, profileId: string) {
|
||||||
icon: 'ti ti-trash',
|
icon: 'ti ti-trash',
|
||||||
action: () => deleteProfile(profileId),
|
action: () => deleteProfile(profileId),
|
||||||
danger: true,
|
danger: true,
|
||||||
}], ev.currentTarget ?? ev.target);
|
}], (ev.currentTarget ?? ev.target ?? undefined) as unknown as HTMLElement | undefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
// streamingのuser storage updateイベントを監視して更新
|
// streamingのuser storage updateイベントを監視して更新
|
||||||
connection?.on('registryUpdated', ({ scope: recievedScope, key, value }) => {
|
connection?.on('registryUpdated', ({ scope: recievedScope, key, value }) => {
|
||||||
if (!recievedScope || recievedScope.length !== scope.length || recievedScope[0] !== scope[0]) return;
|
if (!recievedScope || recievedScope.length !== scope.length || recievedScope[0] !== scope[0]) return;
|
||||||
if (!profiles) return;
|
if (!profiles.value) return;
|
||||||
|
|
||||||
profiles[key] = value;
|
profiles.value[key] = value;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue