WIP: data conflict resolve

pull/1/head
I Made Setia Baruna 2020-11-06 15:24:41 +07:00
parent 925355bc32
commit 8567c6b831
6 changed files with 99 additions and 14 deletions

View File

@ -2,13 +2,13 @@
// doc: /static/images.save_sync_flow.png
import dayjs from 'dayjs';
import { onMount, getContext } from 'svelte';
import { driveSignedIn, driveLoading, saveId } from '../stores/dataSync';
import { onMount, getContext, setContext } from 'svelte';
import { driveSignedIn, driveLoading, saveId, synced } from '../stores/dataSync';
import { getLocalSaveJson, updateSave, updateTime, UPDATE_TIME_KEY } from '../stores/saveManager';
import SyncConflictModal from '../components/SyncConflictModal.svelte';
const { open: openModal } = getContext('simple-modal');
const { open: openModal, close: closeModal } = getContext('simple-modal');
const CLIENT_ID = __paimon.env.GOOGLE_DRIVE_CLIENT_ID;
const API_KEY = __paimon.env.GOOGLE_DRIVE_API_KEY;
@ -19,12 +19,21 @@
$: localSaveExists = $updateTime !== null;
setContext('sync', {
startSync,
});
onMount(() => {
startSync();
});
function startSync() {
synced.set(false);
const script = document.createElement('script');
script.onload = handleClientLoad;
script.src = 'https://apis.google.com/js/api.js';
document.body.appendChild(script);
});
}
function handleClientLoad() {
gapi.load('client:auth2', initClient);
@ -37,6 +46,8 @@
if (status) {
getFiles();
} else {
synced.set(true);
}
}
@ -51,6 +62,22 @@
}
}
async function useRemoteData() {
for (const k in remoteSave) {
updateSave(k, remoteSave[k], true);
}
synced.set(true);
closeModal();
}
async function useLocalData() {
await saveData(getLocalSaveJson());
synced.set(true);
closeModal();
}
async function compareLocalSave() {
try {
const data = await getData();
@ -65,6 +92,8 @@
remoteTime: remoteTime,
localTime: $updateTime,
downloadBackup: exportData,
useRemote: useRemoteData,
useLocal: useLocalData,
},
{
closeButton: false,
@ -73,6 +102,8 @@
styleWindow: { background: '#25294A' },
},
);
} else {
synced.set(true);
}
} catch (err) {
console.error(err);
@ -100,6 +131,7 @@
await compareLocalSave();
} else {
await copyRemoteToLocal();
synced.set(true);
}
}
} catch (err) {
@ -125,6 +157,7 @@
await saveData(getLocalSaveJson());
}
synced.set(true);
console.log(result);
} catch (err) {
console.error(err);
@ -140,6 +173,7 @@
alt: 'media',
});
console.log(result);
return result;
} catch (err) {
console.error(err);
@ -199,3 +233,5 @@
fileLink.click();
}
</script>
<slot />

View File

@ -1,5 +1,5 @@
<script>
import { mdiCloudAlert, mdiContentSave, mdiDownload, mdiFile, mdiGoogleDrive, mdiUpload } from '@mdi/js';
import { mdiCloudAlert, mdiContentSave, mdiDownload, mdiFile, mdiGoogleDrive, mdiLoading, mdiUpload } from '@mdi/js';
import Button from './Button.svelte';
import Icon from './Icon.svelte';
@ -7,6 +7,20 @@
export let remoteTime;
export let localTime;
export let downloadBackup = () => {};
export let useRemote = () => {};
export let useLocal = () => {};
let loading = false;
function useLocalData() {
loading = true;
useLocal();
}
function useRemoteData() {
loading = true;
useRemote();
}
const remoteFormatted = remoteTime.format('dddd, MMMM D, YYYY h:mm A');
const localFormatted = localTime.format('dddd, MMMM D, YYYY h:mm A');
@ -26,8 +40,8 @@
{remoteNewer ? 'NEWER' : 'OLDER'}
</p>
<p class="text-gray-400 mt-1">Last modified: {remoteFormatted}</p>
<Button className="mt-2 w-full">
<Icon path={mdiDownload} className="mr-1" />Replace Local Data
<Button disabled={loading} className="mt-2 w-full" on:click={useRemoteData}>
<Icon path={loading ? mdiLoading : mdiDownload} spin={loading} className="mr-1" />Replace Local Data
</Button>
</div>
<p class="mt-2 text-white text-center">OR</p>
@ -38,8 +52,8 @@
{remoteNewer ? 'OLDER' : 'NEWER'}
</p>
<p class="text-gray-400 mt-1">Last modified: {localFormatted}</p>
<Button className="mt-2 w-full">
<Icon path={mdiUpload} className="mr-1" />Replace Google Drive Data
<Button disabled={loading} className="mt-2 w-full" on:click={useLocalData}>
<Icon path={loading ? mdiLoading : mdiUpload} spin={loading} className="mr-1" />Replace Google Drive Data
</Button>
</div>
<div class="flex mt-6 justify-end">

View File

@ -30,10 +30,11 @@
<Sidebar {segment} mobile />
{/if}
<Modal>
<main style="flex: 1 0 auto;">
<slot />
</main>
<DataSync />
<DataSync>
<main style="flex: 1 0 auto;">
<slot />
</main>
</DataSync>
</Modal>
<p class="lg:ml-64 px-8 py-4 text-gray-600">
Paimon.moe is not affiliated with miHoYo.<br />

View File

@ -23,6 +23,7 @@
});
function readLocalData() {
console.log('wish read local');
const data = readSave(path);
if (data !== null) {
const counterData = JSON.parse(data);

View File

@ -2,5 +2,6 @@ import { writable } from 'svelte/store';
export const driveSignedIn = writable(false);
export const driveLoading = writable(true);
export const synced = writable(true);
export const lastSyncTime = writable(null);
export const synced = writable(false);
export const saveId = writable('');

View File

@ -1,11 +1,25 @@
import dayjs from 'dayjs';
import { writable } from 'svelte/store';
import { synced } from './dataSync';
export const updateTime = writable(null);
export const fromRemote = writable(false);
export const UPDATE_TIME_KEY = 'update-time';
let pendingQueue = [];
let queueSave = true;
const unsubscribe = synced.subscribe((value) => {
console.log('synced:', value);
queueSave = !value;
if (value) {
flushPendingQueue();
}
});
export const checkLocalSave = () => {
const localUpdateTime = localStorage.getItem(UPDATE_TIME_KEY);
if (localUpdateTime !== null) {
@ -19,6 +33,11 @@ export const getLocalSaveJson = () => {
};
export const updateSave = (key, data, isFromRemote) => {
if (queueSave && !isFromRemote) {
pendingQueue.push({ key, data });
return;
}
localStorage.setItem(key, data);
if (!isFromRemote) {
@ -34,3 +53,16 @@ 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;
unsubscribe();
};