Skip to content

Commit

Permalink
Frontend: add classes for some of the state variables.
Browse files Browse the repository at this point in the history
  • Loading branch information
paveloom committed Jun 18, 2024
1 parent cd83f12 commit b930a06
Show file tree
Hide file tree
Showing 7 changed files with 133 additions and 130 deletions.
46 changes: 18 additions & 28 deletions frontend/src/components/Counter.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,23 @@ import ReverseButton from "@/components/buttons/ReverseButton.vue";
import StartButton from "@/components/buttons/StartButton.vue";
import StopButton from "@/components/buttons/StopButton.vue";
import state from "@/state";
import { formatSeconds, hoursToMilliseconds } from "@/utils";
import { state } from "@/store";
import { formatSeconds } from "@/utils";
const nowTime = ref(Date.now());
const isStopping = ref(false);
const currentDifference = computed(() => {
const difference = state.refs.targetDate.value - nowTime.value;
const difference = state.targetDate.value - nowTime.value;
let distance = Math.abs(difference);
if (difference < 0) {
distance *= state.computed.buff.value;
distance *= state.buff.value;
}
return Math.sign(difference) * Math.min(distance, state.refs.maxTime.value);
return Math.sign(difference) * Math.min(distance, state.maxTime.value);
});
const isGameOn = computed(() => {
return state.refs.isReverseOn.value || currentDifference.value > 500;
return state.isReverseOn.value || currentDifference.value > 500;
});
const view = computed(() => {
Expand All @@ -45,7 +45,7 @@ const time = computed(() => {
const elapsedSeconds = Math.round(elapsedMilliseconds / 1000);
return formatSeconds(elapsedSeconds);
} else {
const seconds = state.refs.maxTime.value / 1000;
const seconds = state.maxTime.value / 1000;
return formatSeconds(seconds);
}
});
Expand Down Expand Up @@ -83,46 +83,36 @@ watchEffect(() => {
}
});
function increaseMaxTime() {
state.refs.maxTime.value = Math.min(state.refs.maxTime.maximum, state.refs.maxTime.value + hoursToMilliseconds(1));
}
function decreaseMaxTime() {
state.refs.maxTime.value = Math.max(state.refs.maxTime.minimum, state.refs.maxTime.value - hoursToMilliseconds(1));
}
function reverseTime() {
let difference = currentDifference.value;
if (difference > 0) {
difference /= state.computed.buff.value;
}
state.refs.targetDate.value = nowTime.value - difference;
(difference > 0) && (difference /= state.buff.value);
state.targetDate.value = nowTime.value - difference;
state.refs.isReverseOn.value = !state.refs.isReverseOn.value;
state.isReverseOn.value = !state.isReverseOn.value;
}
function startGame() {
nowTime.value = Date.now();
state.refs.targetDate.value = nowTime.value + state.refs.maxTime.value;
state.targetDate.value = nowTime.value + state.maxTime.value;
}
function stopGame() {
isStopping.value = false;
state.refs.isReverseOn.value = false;
state.refs.targetDate.value = nowTime.value;
state.isReverseOn.value = false;
state.targetDate.value = nowTime.value;
}
function toggleStopping() {
isStopping.value = !isStopping.value;
}
function nextBuff() {
const [buff, prevBuff] = state.nextBuff();
const difference = state.refs.targetDate.value - nowTime.value;
const [buff, prevBuff] = state.buff.next();
const difference = state.targetDate.value - nowTime.value;
let distance = Math.abs(difference);
if (difference < 0) {
distance = distance * prevBuff / buff;
state.refs.targetDate.value = nowTime.value - distance;
state.targetDate.value = nowTime.value - distance;
}
}
</script>
Expand All @@ -133,8 +123,8 @@ function nextBuff() {
<Block v-if="view==='gameOff'">
<StartButton @click="startGame" />
<BuffButton @click="nextBuff" />
<IncreaseMaxTimeButton @click="increaseMaxTime" />
<DecreaseMaxTimeButton @click="decreaseMaxTime" />
<IncreaseMaxTimeButton @click="() => state.maxTime.increment()" />
<DecreaseMaxTimeButton @click="() => state.maxTime.decrement()" />
</Block>
<Block v-else-if="view==='gameOn'">
<ReverseButton @click="reverseTime" />
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/buttons/BuffButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import { computed } from "vue";
import Button from "@/components/Button.vue";
import state from "@/state";
import { state } from "@/store";
const text = computed(() => {
return `${state.computed.buff.value.toFixed(2)}x`;
return `${state.buff.value.toFixed(2)}x`;
});
</script>

Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/buttons/DecreaseMaxTimeButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ defineEmits<{ click: [] }>();
import Button from "@/components/Button.vue";
import state from "@/state";
import { state } from "@/store";
</script>

<template>
<Button
:disabled="state.refs.maxTime.value === state.refs.maxTime.minimum"
:disabled="state.maxTime.value === state.maxTime.minimum"
@click="$emit('click')"
>
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/components/buttons/IncreaseMaxTimeButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ defineEmits<{ click: [] }>();
import Button from "@/components/Button.vue";
import state from "@/state";
import { state } from "@/store";
</script>

<template>
<Button
:disabled="state.refs.maxTime.value === state.refs.maxTime.maximum"
:disabled="state.maxTime.value === state.maxTime.maximum"
@click="$emit('click')"
>
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/components/buttons/ReverseButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ defineEmits<{ click: [] }>();
import Button from "@/components/Button.vue";
import state from "@/state";
import { state } from "@/store";
</script>

<template>
<Button
:class="!state.refs.isReverseOn.value && 'suggested'"
:class="!state.isReverseOn.value && 'suggested'"
@click="$emit('click')"
>
<template v-if="state.refs.isReverseOn.value">
<template v-if="state.isReverseOn.value">
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path class="background" d="M 17.5,6.5 H 6.5 v 11 h 11 z" fill="none" />
<path d="M 9.33333 10.3333 H 10.3333 V 11.3333 H 9.33333 V 10.3333 Z" fill="black" />
Expand Down
125 changes: 32 additions & 93 deletions frontend/src/state.ts
Original file line number Diff line number Diff line change
@@ -1,110 +1,49 @@
import { computed, reactive, ref, watch } from "vue";
import { ref, shallowReactive } from "vue";

import { hoursToMilliseconds } from "@/utils";

export class State {
consts = {
buffs: Array(1 / 0.05 + 1).fill(undefined).map((_, i) => 1 + Math.round(0.05 * i * 100) / 100),
};

refs = {
targetDate: ref(Date.now()),
isReverseOn: ref(false),
maxTime: reactive({
value: hoursToMilliseconds(24),
minimum: hoursToMilliseconds(24),
maximum: hoursToMilliseconds(72),
}),
buffIndex: ref(0),
};

computed = {
buff: computed(() => {
return this.consts.buffs[this.refs.buffIndex.value]!;
}),
};
class Buff {
value = 1.00;

nextBuff(): [number, number] {
const prevBuff = this.consts.buffs[this.refs.buffIndex.value]!;
this.refs.buffIndex.value = (this.refs.buffIndex.value + 1) % this.consts.buffs.length;
const buff = this.consts.buffs[this.refs.buffIndex.value]!;
return [buff, prevBuff];
constructor() {
return shallowReactive(this);
}

* [Symbol.iterator]() {
for (const property in this.refs) {
yield [this.refs[property as keyof typeof this.refs], property] as const;
}
next(): [number, number] {
const prev = this.value;
this.value = Math.round((this.value + 0.05) * 100) / 100;
(this.value > 2.00) && (this.value = 1.00);
return [this.value, prev];
}
}

const IDB_NAME = "flowey";
const OBJECT_STORE_NAME = "state";
class MaxTime {
value = hoursToMilliseconds(24);
minimum = hoursToMilliseconds(24);
maximum = hoursToMilliseconds(72);

class Database {
idb: IDBDatabase | null = null;
state: State = new State();

async init() {
this.idb = await this.openIndexedBD();

for (const [ref, property] of this.state) {
watch(ref, () => {
this.put(ref.value, property);
});
}
};

put(value: unknown, property: string) {
this.idb!
.transaction(OBJECT_STORE_NAME, "readwrite")
.objectStore(OBJECT_STORE_NAME)
.put(value, property);
constructor() {
return shallowReactive(this);
}

private async openIndexedBD() {
return new Promise<IDBDatabase>((resolve) => {
const request = window.indexedDB.open(IDB_NAME);

request.onupgradeneeded = (event) => {
const idb = (event.target as IDBOpenDBRequest).result;
const objectStore = idb.createObjectStore(OBJECT_STORE_NAME);

objectStore.transaction.oncomplete = () => {
const objectStore = idb
.transaction(OBJECT_STORE_NAME, "readwrite")
.objectStore(OBJECT_STORE_NAME);

for (const [ref, property] of this.state) {
objectStore.put(ref.value, property);
}
};
};

request.onsuccess = (event) => {
const idb = (event.target as IDBOpenDBRequest).result;
const objectStore = idb
.transaction(OBJECT_STORE_NAME, "readonly")
.objectStore(OBJECT_STORE_NAME);

for (const [ref, property] of this.state) {
objectStore.get(property).onsuccess = (event) => {
const value: unknown = (event.target as IDBRequest).result;
if (value !== undefined && typeof value === typeof ref.value) {
ref.value = value as typeof ref.value;
return;
}
this.put(ref.value, property);
};
}
increment() {
this.value = Math.min(this.maximum, this.value + hoursToMilliseconds(1));
}

resolve(idb);
};
});
decrement() {
this.value = Math.max(this.minimum, this.value - hoursToMilliseconds(1));
}
}

const database = new Database();
await database.init();
export class State {
buff = new Buff();
isReverseOn = ref(false);
maxTime = new MaxTime();
targetDate = ref(Date.now());

export default database.state;
* [Symbol.iterator]() {
for (const property in this) {
yield [this[property], property] as const;
}
}
}
74 changes: 74 additions & 0 deletions frontend/src/store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { watch } from "vue";

import { State } from "@/state";

const IDB_NAME = "flowey";
const OBJECT_STORE_NAME = "state";

class Store {
idb: IDBDatabase | null = null;
state: State = new State();

async init() {
this.idb = await this.openIndexedBD();

for (const [ref, property] of this.state) {
watch(ref, () => {
this.put(ref.value, property);
});
}
};

put(value: unknown, property: string) {
this.idb!
.transaction(OBJECT_STORE_NAME, "readwrite")
.objectStore(OBJECT_STORE_NAME)
.put(value, property);
}

private async openIndexedBD() {
return new Promise<IDBDatabase>((resolve) => {
const request = window.indexedDB.open(IDB_NAME);

request.onupgradeneeded = (event) => {
const idb = (event.target as IDBOpenDBRequest).result;
const objectStore = idb.createObjectStore(OBJECT_STORE_NAME);

objectStore.transaction.oncomplete = () => {
const objectStore = idb
.transaction(OBJECT_STORE_NAME, "readwrite")
.objectStore(OBJECT_STORE_NAME);

for (const [ref, property] of this.state) {
objectStore.put(ref.value, property);
}
};
};

request.onsuccess = (event) => {
const idb = (event.target as IDBOpenDBRequest).result;
const objectStore = idb
.transaction(OBJECT_STORE_NAME, "readonly")
.objectStore(OBJECT_STORE_NAME);

for (const [ref, property] of this.state) {
objectStore.get(property).onsuccess = (event) => {
const value: unknown = (event.target as IDBRequest).result;
if (value !== undefined && typeof value === typeof ref.value) {
ref.value = value as typeof ref.value;
return;
}
this.put(ref.value, property);
};
}

resolve(idb);
};
});
}
}

const store = new Store();
await store.init();

export const state = store.state;

0 comments on commit b930a06

Please sign in to comment.