mirror of
https://github.com/MadeBaruna/paimon-moe.git
synced 2025-03-14 11:43:52 +01:00
Multiple account support
This commit is contained in:
parent
0e374214a6
commit
7fe43283ac
11 changed files with 294 additions and 42 deletions
|
@ -17,6 +17,7 @@
|
|||
const SCOPES = 'https://www.googleapis.com/auth/drive.appdata';
|
||||
|
||||
let remoteSave = null;
|
||||
let timeout;
|
||||
|
||||
$: localSaveExists = $updateTime !== null;
|
||||
|
||||
|
@ -39,9 +40,19 @@
|
|||
script.onerror = handleError;
|
||||
script.src = 'https://apis.google.com/js/api.js';
|
||||
document.body.appendChild(script);
|
||||
|
||||
timeout = setTimeout(() => {
|
||||
handleError();
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
function cancelTimeout() {
|
||||
console.log('cancelling timeout');
|
||||
if (timeout) clearTimeout(timeout);
|
||||
}
|
||||
|
||||
function handleError() {
|
||||
cancelTimeout();
|
||||
console.log('error loading google drive api');
|
||||
driveSignedIn.set(false);
|
||||
driveLoading.set(false);
|
||||
|
@ -220,6 +231,8 @@
|
|||
}
|
||||
|
||||
function initClient() {
|
||||
console.log('gapi init client');
|
||||
|
||||
gapi.client
|
||||
.init({
|
||||
apiKey: API_KEY,
|
||||
|
@ -229,6 +242,7 @@
|
|||
})
|
||||
.then(
|
||||
function () {
|
||||
cancelTimeout();
|
||||
gapi.auth2.getAuthInstance().isSignedIn.listen(updateSigninStatus);
|
||||
updateSigninStatus(gapi.auth2.getAuthInstance().isSignedIn.get());
|
||||
},
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<script>
|
||||
import { server, ar, wl, loading } from '../stores/server';
|
||||
import { accounts, getAccountPrefix } from '../stores/account';
|
||||
import { readSave, updateSave, fromRemote } from '../stores/saveManager';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
|
@ -18,6 +19,9 @@
|
|||
|
||||
function readLocalData() {
|
||||
loading.set(true);
|
||||
|
||||
const prefix = getAccountPrefix();
|
||||
|
||||
firstLoad = true;
|
||||
|
||||
if (unsubscribeServer) unsubscribeServer();
|
||||
|
@ -25,9 +29,17 @@
|
|||
if (unsubscribeWl) unsubscribeWl();
|
||||
|
||||
console.log('setting read local');
|
||||
const serverSave = readSave('server');
|
||||
const arSave = readSave('ar');
|
||||
const wlSave = readSave('wl');
|
||||
const accountsSave = readSave('accounts');
|
||||
const serverSave = readSave(`${prefix}server`);
|
||||
const arSave = readSave(`${prefix}ar`);
|
||||
const wlSave = readSave(`${prefix}wl`);
|
||||
if (accountsSave !== null) {
|
||||
const accountList = accountsSave.split(',').map((e) => ({
|
||||
label: `Account ${e.substring(7)}`,
|
||||
value: e,
|
||||
}));
|
||||
accounts.set([{ label: 'Main', value: 'main' }, ...accountList]);
|
||||
}
|
||||
if (serverSave !== null) {
|
||||
const currentServer = serverSave;
|
||||
server.set(currentServer);
|
||||
|
@ -42,20 +54,23 @@
|
|||
unsubscribeServer = server.subscribe((val) => {
|
||||
if (firstLoad) return;
|
||||
|
||||
const prefix = getAccountPrefix();
|
||||
console.log('server changed', val);
|
||||
updateSave('server', val);
|
||||
updateSave(`${prefix}server`, val);
|
||||
});
|
||||
unsubscribeWl = wl.subscribe((val) => {
|
||||
if (firstLoad) return;
|
||||
|
||||
const prefix = getAccountPrefix();
|
||||
console.log('wl changed', val);
|
||||
updateSave('wl', val);
|
||||
updateSave(`${prefix}wl`, val);
|
||||
});
|
||||
unsubscribeAr = ar.subscribe((val) => {
|
||||
if (firstLoad) return;
|
||||
|
||||
const prefix = getAccountPrefix();
|
||||
console.log('ar changed', val);
|
||||
updateSave('ar', val);
|
||||
updateSave(`${prefix}ar`, val);
|
||||
});
|
||||
|
||||
firstLoad = false;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
import { todos, loading } from '../stores/todo';
|
||||
import { readSave, updateSave, fromRemote } from '../stores/saveManager';
|
||||
import { onMount } from 'svelte';
|
||||
import { getAccountPrefix, selectedAccount } from '../stores/account';
|
||||
|
||||
let unsubscribe = null;
|
||||
let firstLoad = true;
|
||||
|
@ -12,6 +13,13 @@
|
|||
|
||||
onMount(() => {
|
||||
readLocalData();
|
||||
|
||||
const unsub = selectedAccount.subscribe(() => {
|
||||
console.log('account changed, reading todo for the account');
|
||||
readLocalData();
|
||||
});
|
||||
|
||||
return () => unsub();
|
||||
});
|
||||
|
||||
function readLocalData() {
|
||||
|
@ -20,17 +28,21 @@
|
|||
|
||||
if (unsubscribe) unsubscribe();
|
||||
|
||||
const prefix = getAccountPrefix();
|
||||
|
||||
console.log('todo read local');
|
||||
const data = readSave('todos');
|
||||
const data = readSave(`${prefix}todos`);
|
||||
if (data !== null) {
|
||||
const todoList = JSON.parse(data);
|
||||
todos.set(todoList);
|
||||
} else {
|
||||
todos.set([]);
|
||||
}
|
||||
|
||||
unsubscribe = todos.subscribe((val) => {
|
||||
if (firstLoad) return;
|
||||
|
||||
updateSave('todos', JSON.stringify(val));
|
||||
updateSave(`${prefix}todos`, JSON.stringify(val));
|
||||
});
|
||||
|
||||
firstLoad = false;
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
import { weaponList } from '../data/weaponList';
|
||||
import { characters } from '../data/characters';
|
||||
import { readSave, updateSave } from '../stores/saveManager';
|
||||
import { getAccountPrefix } from '../stores/account';
|
||||
|
||||
export let processFirstTimePopup;
|
||||
export let closeModal;
|
||||
|
@ -255,8 +256,9 @@
|
|||
return new dayjs().year(2000).unix();
|
||||
}
|
||||
|
||||
const prefix = getAccountPrefix();
|
||||
const path = `wish-counter-${type.id}`;
|
||||
const localData = readSave(path);
|
||||
const localData = readSave(`${prefix}${path}`);
|
||||
|
||||
let localWishes = [];
|
||||
if (localData !== null) {
|
||||
|
@ -380,8 +382,9 @@
|
|||
if (wishes[code] === undefined) return;
|
||||
console.log('processing', type.name);
|
||||
|
||||
const prefix = getAccountPrefix();
|
||||
const path = `wish-counter-${type.id}`;
|
||||
const localData = readSave(path);
|
||||
const localData = readSave(`${prefix}${path}`);
|
||||
|
||||
let localWishes = [];
|
||||
if (localData !== null) {
|
||||
|
@ -434,7 +437,7 @@
|
|||
pulls: combined,
|
||||
});
|
||||
|
||||
updateSave(path, data);
|
||||
updateSave(`${prefix}${path}`, data);
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
|
|
16
src/routes/settings/_deleteAccount.svelte
Normal file
16
src/routes/settings/_deleteAccount.svelte
Normal file
|
@ -0,0 +1,16 @@
|
|||
<script>
|
||||
import Button from '../../components/Button.svelte';
|
||||
|
||||
export let account;
|
||||
export let deleteAccount;
|
||||
export let cancel;
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<p class="text-white font-bold mb-4 text-lg">Delete {account.label}?</p>
|
||||
<p class="text-white mb-4">All todo and wish history data will be deleted</p>
|
||||
<div class="flex justify-end gap-2">
|
||||
<Button on:click={cancel}>Cancel</Button>
|
||||
<Button on:click={deleteAccount} color="red">Delete</Button>
|
||||
</div>
|
||||
</div>
|
16
src/routes/settings/_resetAccount.svelte
Normal file
16
src/routes/settings/_resetAccount.svelte
Normal file
|
@ -0,0 +1,16 @@
|
|||
<script>
|
||||
import Button from '../../components/Button.svelte';
|
||||
|
||||
export let account;
|
||||
export let resetAccount;
|
||||
export let cancel;
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<p class="text-white font-bold mb-4 text-lg">Reset {account.label}?</p>
|
||||
<p class="text-white mb-4">All todo and wish history data will be deleted</p>
|
||||
<div class="flex justify-end gap-2">
|
||||
<Button on:click={cancel}>Cancel</Button>
|
||||
<Button on:click={resetAccount} color="red">Reset</Button>
|
||||
</div>
|
||||
</div>
|
|
@ -1,15 +1,24 @@
|
|||
<script>
|
||||
import { mdiCheckCircleOutline, mdiChevronDown, mdiDiscord, mdiGithub, mdiGoogleDrive, mdiLoading } from '@mdi/js';
|
||||
import { onMount } from 'svelte';
|
||||
import { getContext, onMount } from 'svelte';
|
||||
import { slide } from 'svelte/transition';
|
||||
|
||||
import Button from '../components/Button.svelte';
|
||||
import Icon from '../components/Icon.svelte';
|
||||
import Select from '../components/Select.svelte';
|
||||
import Input from '../components/Input.svelte';
|
||||
import Button from '../../components/Button.svelte';
|
||||
import Icon from '../../components/Icon.svelte';
|
||||
import Select from '../../components/Select.svelte';
|
||||
import Input from '../../components/Input.svelte';
|
||||
import DeleteAccountModal from './_deleteAccount.svelte';
|
||||
import ResetAccountModal from './_resetAccount.svelte';
|
||||
|
||||
import { driveSignedIn, driveError, driveLoading, synced, localModified, lastSyncTime } from '../stores/dataSync';
|
||||
import { server, ar, wl } from '../stores/server';
|
||||
import { driveSignedIn, driveError, driveLoading, synced, localModified, lastSyncTime } from '../../stores/dataSync';
|
||||
import { server, ar, wl } from '../../stores/server';
|
||||
import { accounts, getAccountPrefix, selectedAccount } from '../../stores/account';
|
||||
import { pushToast } from '../../stores/toast';
|
||||
import { readSave, updateSave } from '../../stores/saveManager';
|
||||
|
||||
const { open: openModal, close: closeModal } = getContext('simple-modal');
|
||||
|
||||
let currentAccount = $selectedAccount;
|
||||
|
||||
const servers = [
|
||||
{ label: 'Asia/TW/HK/MO', value: 'Asia' },
|
||||
|
@ -17,6 +26,7 @@
|
|||
{ label: 'Europe', value: 'Europe' },
|
||||
];
|
||||
|
||||
let mounted = false;
|
||||
let selectedServer = null;
|
||||
let arInput = '';
|
||||
let wlInput = '';
|
||||
|
@ -67,6 +77,155 @@
|
|||
}
|
||||
}
|
||||
|
||||
function addAccount() {
|
||||
const accountList = $accounts;
|
||||
const accountNumber =
|
||||
accountList.length === 1 ? 2 : Number(accountList[accountList.length - 1].value.substring(7)) + 1;
|
||||
|
||||
const newAccount = { label: `Account ${accountNumber}`, value: `account${accountNumber}` };
|
||||
const updatedAccountList = [...accountList, newAccount];
|
||||
accounts.set(updatedAccountList);
|
||||
|
||||
updateSave(
|
||||
'accounts',
|
||||
updatedAccountList
|
||||
.slice(1)
|
||||
.map((e) => e.value)
|
||||
.join(','),
|
||||
);
|
||||
|
||||
pushToast(`Account ${accountNumber} added, select it on the account list!`);
|
||||
}
|
||||
|
||||
function selectAccount() {
|
||||
if (!mounted) return;
|
||||
|
||||
console.log('changed account to', currentAccount.label);
|
||||
|
||||
selectedAccount.set(currentAccount);
|
||||
const prefix = getAccountPrefix();
|
||||
|
||||
const serverSave = readSave(`${prefix}server`);
|
||||
if (serverSave === null) {
|
||||
selectedServer = { label: 'Asia/TW/HK/MO', value: 'Asia' };
|
||||
} else {
|
||||
const serverSave = readSave(`${prefix}server`);
|
||||
selectedServer = servers.find((e) => e.value === serverSave);
|
||||
}
|
||||
|
||||
const arSave = readSave(`${prefix}ar`);
|
||||
if (arSave === null) {
|
||||
arInput = '45';
|
||||
} else {
|
||||
arInput = arSave;
|
||||
}
|
||||
|
||||
const wlSave = readSave(`${prefix}wl`);
|
||||
if (wlSave === null) {
|
||||
wlInput = '6';
|
||||
} else {
|
||||
wlInput = wlSave;
|
||||
}
|
||||
}
|
||||
|
||||
function deleteAccount() {
|
||||
const prefix = getAccountPrefix();
|
||||
|
||||
const updatedList = $accounts.filter((e) => e.value !== currentAccount.value);
|
||||
|
||||
currentAccount = { label: 'Main', value: 'main' };
|
||||
selectedAccount.set(currentAccount);
|
||||
|
||||
accounts.set(updatedList);
|
||||
|
||||
const keyWillBeDeleted = [
|
||||
'server',
|
||||
'ar',
|
||||
'wl',
|
||||
'todos',
|
||||
'wish-counter-character-event',
|
||||
'wish-counter-weapon-event',
|
||||
'wish-counter-standard',
|
||||
'wish-counter-beginners',
|
||||
];
|
||||
|
||||
for (let k of keyWillBeDeleted) {
|
||||
localStorage.removeItem(`${prefix}${k}`);
|
||||
}
|
||||
|
||||
if (updatedList.length > 1) {
|
||||
updateSave(
|
||||
'accounts',
|
||||
updatedList
|
||||
.slice(1)
|
||||
.map((e) => e.value)
|
||||
.join(','),
|
||||
);
|
||||
} else {
|
||||
updateSave('accounts', undefined);
|
||||
}
|
||||
|
||||
pushToast('Data deleted');
|
||||
closeModal();
|
||||
}
|
||||
|
||||
function resetAccount() {
|
||||
const prefix = getAccountPrefix();
|
||||
|
||||
const keyWillBeDeleted = [
|
||||
'todos',
|
||||
'wish-counter-character-event',
|
||||
'wish-counter-weapon-event',
|
||||
'wish-counter-standard',
|
||||
'wish-counter-beginners',
|
||||
];
|
||||
|
||||
for (let k of keyWillBeDeleted) {
|
||||
localStorage.removeItem(`${prefix}${k}`);
|
||||
}
|
||||
|
||||
updateSave(`${prefix}todos`, undefined, true);
|
||||
updateSave(`${prefix}todos`, JSON.stringify([]));
|
||||
|
||||
pushToast('Data deleted');
|
||||
closeModal();
|
||||
}
|
||||
|
||||
function openDeleteAccount() {
|
||||
openModal(
|
||||
DeleteAccountModal,
|
||||
{
|
||||
cancel: closeModal,
|
||||
account: currentAccount,
|
||||
deleteAccount: deleteAccount,
|
||||
},
|
||||
{
|
||||
closeButton: false,
|
||||
styleWindow: { background: '#25294A', width: '300px' },
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function openResetAccount() {
|
||||
openModal(
|
||||
ResetAccountModal,
|
||||
{
|
||||
cancel: closeModal,
|
||||
account: currentAccount,
|
||||
resetAccount: resetAccount,
|
||||
},
|
||||
{
|
||||
closeButton: false,
|
||||
styleWindow: { background: '#25294A', width: '300px' },
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
mounted = true;
|
||||
});
|
||||
|
||||
$: currentAccount, selectAccount();
|
||||
$: selectedServer, updateServer();
|
||||
$: arInput, updateAR();
|
||||
$: wlInput, updateWL();
|
||||
|
@ -82,6 +241,22 @@
|
|||
<div class="bg-item rounded-xl mb-4 p-4">
|
||||
<p class="text-white">Data Version: <b>1.3</b></p>
|
||||
</div>
|
||||
<div class="bg-item rounded-xl mb-4 p-4 flex flex-col">
|
||||
<p class="text-white">Have multiple account? Choose account here to separate your wish and todo data</p>
|
||||
<div class="flex mt-2">
|
||||
<Select
|
||||
className="w-64 mr-2"
|
||||
bind:selected={currentAccount}
|
||||
options={$accounts}
|
||||
placeholder="Select your account"
|
||||
/>
|
||||
<Button on:click={openResetAccount} className="mr-2 w-24" color="red">Reset</Button>
|
||||
{#if currentAccount.value !== 'main'}
|
||||
<Button on:click={openDeleteAccount} className="mr-2 w-24" color="red">Delete</Button>
|
||||
{/if}
|
||||
<Button className="w-24" on:click={addAccount}>Add</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-item rounded-xl mb-4 p-4 flex flex-col md:flex-row">
|
||||
<div class="flex flex-col md:flex-row md:items-center mr-2">
|
||||
<p class="text-white mr-2">Select your server:</p>
|
|
@ -15,6 +15,7 @@
|
|||
import { characters } from '../../data/characters';
|
||||
import dayjs from 'dayjs';
|
||||
import { weaponList } from '../../data/weaponList';
|
||||
import { getAccountPrefix } from '../../stores/account';
|
||||
|
||||
let numberFormat = Intl.NumberFormat();
|
||||
|
||||
|
@ -153,7 +154,8 @@
|
|||
|
||||
export function readLocalData() {
|
||||
console.log('wish read local');
|
||||
const data = readSave(path);
|
||||
const prefix = getAccountPrefix();
|
||||
const data = readSave(`${prefix}${path}`);
|
||||
if (data !== null) {
|
||||
const counterData = JSON.parse(data);
|
||||
total = counterData.total;
|
||||
|
@ -171,7 +173,8 @@
|
|||
pulls,
|
||||
});
|
||||
|
||||
updateSave(path, data);
|
||||
const prefix = getAccountPrefix();
|
||||
updateSave(`${prefix}${path}`, data);
|
||||
}, 2000);
|
||||
|
||||
function add(val) {
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
import { characters } from '../../data/characters';
|
||||
import { weaponList } from '../../data/weaponList';
|
||||
|
||||
import { getAccountPrefix } from '../../stores/account';
|
||||
import { readSave, updateTime, fromRemote } from '../../stores/saveManager';
|
||||
import SummaryItem from './_summaryItem.svelte';
|
||||
|
||||
|
@ -46,10 +47,11 @@
|
|||
export function readLocalData() {
|
||||
totalWish = 0;
|
||||
console.log('wish summary read local');
|
||||
const prefix = getAccountPrefix();
|
||||
|
||||
for (let type of types) {
|
||||
const path = `wish-counter-${type.id}`;
|
||||
const data = readSave(path);
|
||||
const data = readSave(`${prefix}${path}`);
|
||||
if (data !== null) {
|
||||
const counterData = JSON.parse(data);
|
||||
const pulls = counterData.pulls || [];
|
||||
|
|
13
src/stores/account.js
Normal file
13
src/stores/account.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
import { get, writable } from 'svelte/store';
|
||||
|
||||
export const accounts = writable([{ label: 'Main', value: 'main' }]);
|
||||
export const selectedAccount = writable({ label: 'Main', value: 'main' });
|
||||
|
||||
export const getAccountPrefix = () => {
|
||||
const current = get(selectedAccount);
|
||||
if (current.value === 'main') {
|
||||
return '';
|
||||
} else {
|
||||
return `${current.value}-`;
|
||||
}
|
||||
};
|
|
@ -10,8 +10,6 @@ export const fromRemote = writable(false);
|
|||
|
||||
export const UPDATE_TIME_KEY = 'update-time';
|
||||
|
||||
let pendingQueue = [];
|
||||
let queueSave = true;
|
||||
let saveFileId = '';
|
||||
let signedIn = false;
|
||||
|
||||
|
@ -53,10 +51,8 @@ async function saveData(data) {
|
|||
|
||||
synced.subscribe((value) => {
|
||||
console.log('synced:', value);
|
||||
queueSave = !value;
|
||||
|
||||
if (value) {
|
||||
flushPendingQueue();
|
||||
lastSyncTime.set(dayjs());
|
||||
}
|
||||
});
|
||||
|
@ -78,13 +74,12 @@ export const updateSave = (key, data, isFromRemote) => {
|
|||
localModified.set(true);
|
||||
}
|
||||
|
||||
if (queueSave && !isFromRemote) {
|
||||
pendingQueue.push({ key, data });
|
||||
return;
|
||||
if (data !== undefined) {
|
||||
localStorage.setItem(key, data);
|
||||
} else {
|
||||
localStorage.removeItem(key);
|
||||
}
|
||||
|
||||
localStorage.setItem(key, data);
|
||||
|
||||
if (!isFromRemote) {
|
||||
const currentTime = dayjs();
|
||||
updateTime.set(currentTime);
|
||||
|
@ -102,15 +97,3 @@ export const readSave = (key) => {
|
|||
const data = localStorage.getItem(key);
|
||||
return data;
|
||||
};
|
||||
|
||||
export const flushPendingQueue = () => {
|
||||
console.log('flushing save queue');
|
||||
console.log(pendingQueue);
|
||||
|
||||
for (const item of pendingQueue) {
|
||||
updateSave(item.key, item.data);
|
||||
}
|
||||
|
||||
pendingQueue = [];
|
||||
queueSave = false;
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue