Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: settings modal, new header, listener handling refactor #3

Merged
merged 3 commits into from
Apr 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,10 @@ An _ActionLog_ viewer for [PSO2:NGS©️](https://pso2.com/), but in Tauri this

---

## Previews (v1.0.4)
## Previews (v1.0.2)

![Filled Item Log](web/public/images/preview-filled-log.png)
![Settings](web/public/images/preview-settings.png)

---

Expand Down
2 changes: 1 addition & 1 deletion app/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "nt-ngs-log-observer",
"version": "1.0.1",
"version": "1.0.2",
"description": "Action Log observer for PSO2:NGS",
"author": "jojobii-arks",
"private": true,
Expand Down
22 changes: 19 additions & 3 deletions app/src/lib/getGameDirectory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ export default async function getGameDirectory() {
const documentDirPath = await join(await documentDir(), 'SEGA');
const entries = await readDir(documentDirPath);
const pso2Directories = entries.filter((entry) => entry.name?.includes('PHANTASYSTARONLINE2'));
console.log(pso2Directories);

const pso2DirectoriesWithMetadata = await Promise.all(
pso2Directories.map(async (directory) => {
Expand All @@ -24,7 +23,24 @@ export default async function getGameDirectory() {
const pso2GameLogDirectory = await join(pso2DirectoryToUse.path, 'log_ngs');

return {
gameDirectoryPath: pso2DirectoryToUse.path,
gameLogDirectoryPath: pso2GameLogDirectory
game: {
path: pso2DirectoryToUse.path,
label: pso2DirectoryToUse.path.split('\\').at(-1) as string
},
log: {
path: pso2GameLogDirectory,
label: pso2GameLogDirectory.split('\\').at(-1) as string
}
};
}

export type GameDirectory = {
game: {
path: string | null;
label: string | null;
};
log: {
path: string | null;
label: string | null;
};
};
154 changes: 67 additions & 87 deletions app/src/lib/stores/logs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { readBinaryFile, readDir } from '@tauri-apps/api/fs';
import { diffLines } from 'diff';
import parseActionLog from '$lib/parseActionLog';
import { metadata } from 'tauri-plugin-fs-extra-api';
import { readable } from 'svelte/store';
import { get, writable } from 'svelte/store';
import type { ActionLogItem } from '$lib/types';

const encoding = 'utf-16le';
Expand All @@ -15,94 +15,74 @@ async function readEncodedTextFile(path: string) {
return new TextDecoder(encoding).decode(data);
}

const logsArray: ActionLogItem[] = [];
export const logs = writable<ActionLogItem[]>([]);

export const gameDirectory = readable<{
game: { path: string | null; label: string | null };
log: { path: string | null; label: string | null };
}>({ game: { path: null, label: null }, log: { path: null, label: null } }, function start(set) {
(async () => {
const gameDirectory = await getGameDirectory();
set({
game: {
path: gameDirectory.gameDirectoryPath,
label: gameDirectory.gameDirectoryPath.split('\\').at(-1) as string
},
log: {
path: gameDirectory.gameLogDirectoryPath,
label: gameDirectory.gameLogDirectoryPath.split('\\').at(-1) as string
}
});
})();
});
let detacher = () => {
console.log('Detacher not initialized.');
};

export const logs = readable(logsArray, function start(set) {
let stop;

(async () => {
const datamap: Record<string, string> = {};
const pso2GameLogDirectory = (await getGameDirectory()).gameLogDirectoryPath;

/** Grab initial data */
(await readDir(pso2GameLogDirectory)).filter(async (file) => {
const meta = await metadata(file.path);
const metaAge = new Date().getTime() - new Date(meta.modifiedAt).getTime();
if (metaAge >= twoDays) {
return;
}

const data = await readEncodedTextFile(file.path);

/**
* The following sequence blocks the main thread. Maybe rewrite the parsing to be 100% in Rust?
*/
// if (!data.length) return false;
// const actionLog = await parseActionLog(data);
// const age =
// new Date().getTime() - new Date(actionLog[actionLog.length - 1].log_time).getTime();

// if (age >= twoDays) {
// return;
// }
export function detachListeners() {
detacher();
}

datamap[file.path] = data;
export async function initializeLogListener() {
console.count('Initializing log listener...');
const datamap: Record<string, string> = {};
const pso2GameLogDirectory = (await getGameDirectory()).log.path;

/** Grab initial data */
(await readDir(pso2GameLogDirectory)).filter(async (file) => {
const meta = await metadata(file.path);
const metaAge = new Date().getTime() - new Date(meta.modifiedAt).getTime();
if (metaAge >= twoDays) {
return;
});

const polling = setInterval(async () => {
/** Poll the game log directory for changes. */
await readDir(pso2GameLogDirectory);
}, 1000);

const stopWatching = await watchImmediate(
pso2GameLogDirectory,
{ recursive: true },
async (event) => {
const {
paths: [path]
} = event;
console.log('change found', path);
const data = await readEncodedTextFile(path);

diffLines(datamap[path], data).forEach(async (part) => {
if (part.added) {
datamap[path] = data;
const actionLog = await parseActionLog(part.value);
console.log('new events', actionLog);
logsArray.push(...actionLog);
set(logsArray);
}
});
}
);

/** Set stop function for store. */
stop = () => {
clearInterval(polling);
stopWatching();
};
})();

return stop;
});
}

const data = await readEncodedTextFile(file.path);

datamap[file.path] = data;

return;
});

const polling = setInterval(async () => {
/** Poll the game log directory for changes. */
await readDir(pso2GameLogDirectory);
}, 1000);

const stopWatching = await watchImmediate(
pso2GameLogDirectory,
{ recursive: true },
async (event) => {
const {
paths: [path]
} = event;
console.log('change found', path);
const data = await readEncodedTextFile(path);

diffLines(datamap[path], data).forEach(async (part) => {
if (part.added) {
datamap[path] = data;
const actionLog = await parseActionLog(part.value);
console.log('new events', actionLog);
logs.set([...get(logs), ...actionLog]);
}
});
}
);

detacher = () => {
console.log('Stopping log listener via detacher...');
console.countReset('Initializing log listener...');
clearInterval(polling);
stopWatching();
};

/** Stop function for listener. */
return () => {
console.log('Stopping log listener...');
console.countReset('Initializing log listener...');
clearInterval(polling);
stopWatching();
};
}
22 changes: 22 additions & 0 deletions app/src/lib/stores/metadata.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { writable } from 'svelte/store';

export const metadata = writable({
appName: '',
appVersion: '',
tauriVersion: '',
gameDirectoryPath: '',
gameDirectoryLabel: ''
});

import { getName, getVersion, getTauriVersion } from '@tauri-apps/api/app';
import getGameDirectory from '$lib/getGameDirectory';
(async () => {
const gameDirectory = await getGameDirectory();
metadata.set({
appName: await getName(),
appVersion: await getVersion(),
tauriVersion: await getTauriVersion(),
gameDirectoryPath: gameDirectory.game.path,
gameDirectoryLabel: gameDirectory.game.label
});
})();
9 changes: 9 additions & 0 deletions app/src/lib/stores/settings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { writable } from 'svelte/store';

const defaultSettings = {
showMeseta: true,
isAlwaysOnTop: false,
amountToDisplay: 25
};

export const settings = writable(defaultSettings);
45 changes: 43 additions & 2 deletions app/src/routes/+layout.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,32 @@
import windowMinimize from '$lib/svg/window-minimize.svg';
import windowMaximize from '$lib/svg/window-maximize.svg';
import windowClose from '$lib/svg/window-close.svg';

/** Handle listeners within lifecycle. */
import { initializeLogListener, detachListeners } from '$lib/stores/logs';
import { onMount } from 'svelte';
onMount(async () => {
/** Detach listeners if there are any; mainly for development. */
detachListeners();

/** Initialize listeners.*/
const closeLogListener = await initializeLogListener();

return async () => {
console.log('dismounting');
closeLogListener();
};
});

/** Listen to changes for isAlwaysOnTop */
import { settings } from '$lib/stores/settings';
$: appWindow.setAlwaysOnTop($settings.isAlwaysOnTop).catch(console.error);

import Settings from './Settings.svelte';
</script>

<!-- Window Controls -->
<div class="flex gap-0 absolute top-0 right-0 text-white select-none">
<div class="z-[1000] flex gap-0 absolute top-0 right-0 text-white select-none">
<button on:click={() => appWindow.minimize()}>
<img src={windowMinimize} alt="minimize" />
</button>
Expand All @@ -23,7 +45,26 @@
</button>
</div>

<slot />
<main class="flex max-h-[100vh] max-w-[100vw] flex-col overflow-y-hidden">
<!-- Header -->
<div data-tauri-drag-region class="bg-base-300">
<label for="my-modal-4" class="btn btn-ghost normal-case font-black text-xl overflow-hidden"
>NGS Log Observer</label
>
</div>

<!-- Modal -->
<input type="checkbox" id="my-modal-4" class="modal-toggle" />
<label for="my-modal-4" class="modal">
<label class="modal-box relative bg-base-200" for="">
<label for="my-modal-4" class="btn btn-sm btn-circle absolute right-2 top-2">✕</label>

<Settings />
</label>
</label>

<slot />
</main>

<style lang="postcss">
button {
Expand Down
Loading