Multiple account support

pull/1/head
Made Baruna 2021-03-13 21:20:52 +08:00
parent 0e374214a6
commit 7fe43283ac
11 changed files with 294 additions and 42 deletions

View File

@ -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());
},

View File

@ -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;

View File

@ -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;

View File

@ -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(() => {

View 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>

View 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>

View File

@ -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>

View File

@ -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) {

View File

@ -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
View 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}-`;
}
};

View File

@ -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;
};