From a7d7b92eda688cc1509ca4fd4d7d3220936b8427 Mon Sep 17 00:00:00 2001 From: Alexander Guryanov Date: Fri, 22 Dec 2023 15:04:29 +0600 Subject: [PATCH] v0.80.2 --- index.html | 4 +- package.json | 2 +- src/frame/account-frame.tsx | 22 +++++++++- src/i18n.ts | 8 +++- src/sidebar/sidebar-button.tsx | 75 +++++++++++++++++++++++++++++++++- src/sidebar/sidebar.css | 5 +++ src/sidebar/sidebar.tsx | 3 +- src/store/auth.ts | 1 + src/store/dos.ts | 2 +- src/v8/config.ts | 5 +++ src/window/dos/render/webgl.ts | 11 +++-- yarn.lock | 8 ++-- 12 files changed, 128 insertions(+), 18 deletions(-) diff --git a/index.html b/index.html index 20bdd794..09e75dab 100644 --- a/index.html +++ b/index.html @@ -22,8 +22,6 @@ const params = new URLSearchParams(location.search); document.addEventListener("DOMContentLoaded", () => { /* eslint-disable max-len */ - // const url = "https://cdn.dos.zone/original/2X/7/744842062905f72648a4d492ccc2526d039b3702.jsdos"; // sim-city - // const url = "https://cdn.dos.zone/original/2X/b/b4b5275904d86a4ab8a20917b2b7e34f0df47bf7.jsdos"; // dhry2 /* eslint-enable max-len */ const props = Dos(document.getElementById("app"), { @@ -34,6 +32,8 @@ // url: "https://cdn.dos.zone/custom/dos/duke3d_ipx.jsdos", // url: "https://br.cdn.dos.zone/ipx/duke3d/duke3d_ipx.jsdos", // url: "https://br.cdn.dos.zone/ipx/doom_dm/doom_dm.jsdos", + // url: "https://cdn.dos.zone/original/2X/b/b4b5275904d86a4ab8a20917b2b7e34f0df47bf7.jsdos", // dhry2 + // url: "https://cdn.dos.zone/original/2X/7/744842062905f72648a4d492ccc2526d039b3702.jsdos", // sim-city pathPrefix: "/emulators/", server: params.get("server"), room: params.get("room"), diff --git a/package.json b/package.json index dc63f2ff..5c33eabd 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ "@typescript-eslint/parser": "^6.9.0", "autoprefixer": "^10.4.16", "daisyui": "^3.9.3", - "emulators": "0.80.20", + "emulators": "0.80.22", "eslint": "^8.52.0", "eslint-config-google": "^0.14.0", "postcss": "^8.4.31", diff --git a/src/frame/account-frame.tsx b/src/frame/account-frame.tsx index a6fb1f14..12c2605b 100644 --- a/src/frame/account-frame.tsx +++ b/src/frame/account-frame.tsx @@ -5,6 +5,7 @@ import { authSlice } from "../store/auth"; import { useT } from "../i18n"; import { State } from "../store"; import { linkToBuy } from "../v8/subscriptions"; +import { cancelSubscription } from "../v8/config"; export function AccountFrame(props: {}) { const t = useT(); @@ -34,6 +35,7 @@ export function AccountFrame(props: {}) { function PremiumPlan(props: {}) { const t = useT(); + const lang = useSelector((state: State) => state.i18n.lang); const account = useSelector((state: State) => state.auth.account); const [locked, setLocked] = useState(false); @@ -59,7 +61,17 @@ function PremiumPlan(props: {}) { } return
-
{t("premium")}
+
+ + {t("premium")} +
+ {account.premium && + + {t("cancle")} + } +
{!account.premium && <>
@@ -87,7 +99,13 @@ function PremiumPlan(props: {}) {
-
{t("game_no_limits")}
+
{t("writeable_fat32")}
+
+ + {t("manage")} +
diff --git a/src/i18n.ts b/src/i18n.ts index cde20417..8916299d 100644 --- a/src/i18n.ts +++ b/src/i18n.ts @@ -11,7 +11,7 @@ const translations: {[lang: string]: {[key: string]: string} } = { buy: "Купить", experimental_features: "Доступ к экспериентальным функциям", cloud_saves: "Облачные сохранения", - game_no_limits: "Любой размер игры", + writeable_fat32: "FAT32 диски", net_no_limits: "Выбор сервера для стевой игры", unlock_options: "Доступ ко всем настройкам", error: "Упс... Что-то пошло не так...", @@ -63,6 +63,8 @@ const translations: {[lang: string]: {[key: string]: string} } = { read_only_access: "Диск FAT32 открыт только для чтения", fix: "Исправить", close: "Закрыть", + cancle: "Отказаться", + manage: "Управлять", }, en: { logout: "Logout", @@ -72,7 +74,7 @@ const translations: {[lang: string]: {[key: string]: string} } = { buy: "Buy", experimental_features: "Access to all experimental features", cloud_saves: "Cloud saves", - game_no_limits: "Unlimited game size", + writeable_fat32: "Writable FAT32", net_no_limits: "Change the network region", unlock_options: "Unlock all configuration options", error: "Oops... Something went wrong...", @@ -124,6 +126,8 @@ const translations: {[lang: string]: {[key: string]: string} } = { read_only_access: "The FAT32 drive is open in read-only mode", fix: "Fix", close: "Close", + cancle: "Cancle", + manage: "Manage", }, }; diff --git a/src/sidebar/sidebar-button.tsx b/src/sidebar/sidebar-button.tsx index 44498131..81f3936c 100644 --- a/src/sidebar/sidebar-button.tsx +++ b/src/sidebar/sidebar-button.tsx @@ -1,9 +1,10 @@ import { AnyAction } from "@reduxjs/toolkit"; import { useDispatch, useSelector } from "react-redux"; import { LockBadge } from "../components/lock"; -import { State } from "../store"; +import { State, store } from "../store"; import { Frame, uiSlice } from "../store/ui"; import { DisketteIcon } from "./diskette-icon"; +import { useEffect, useRef, useState } from "preact/hooks"; export function ImageRenderingButton(props: { class?: string, @@ -114,6 +115,78 @@ export function CyclesButton() { ; } +export function HddLed(props: {}) { + const ref = useRef(null); + const [state] = useState<{ + recv: number, enabled: boolean, delayLedTo: number, + }>({ recv: 0, enabled: false, delayLedTo: 0 }); + + useEffect(() => { + if (ref.current) { + const el = ref.current; + el.classList.add("bg-base-300"); + + const id = setInterval(() => { + if (state.delayLedTo <= Date.now()) { + const newRecv = store.getState().dos.stats.driveRecv; + const newEnabled = state.recv !== newRecv; + if (newEnabled !== state.enabled) { + el.classList.remove("bg-base-300", "bg-green-300", "animate-led"); + if (newEnabled) { + el.classList.add("bg-green-300", "animate-led"); + } else { + el.classList.add("bg-base-300"); + } + state.enabled = newEnabled; + } + + if (newEnabled) { + state.delayLedTo = Date.now() + 300 + Math.random() * 1500; + } else { + state.delayLedTo = 0; + } + + state.recv = newRecv; + } + }, 150); + + return () => { + el.classList.remove("bg-base-300", "bg-green-300", "animate-led"); + clearInterval(id); + }; + } + }, [ref, state]); + const [on, setOn] = useState(false); + const [off, setOff] = useState<{ recv: number, timeoutId: number | null }>({ + recv: 0, + timeoutId: null, + }); + const statsRecv = useSelector((state: State) => state.dos.stats.driveRecv); + if (off.recv !== statsRecv) { + if (!on) { + setOn(true); + } + + if (off.timeoutId) { + clearTimeout(off.timeoutId); + } + + const id = setTimeout(() => { + setOn(false); + setOff({ + recv: statsRecv, + timeoutId: null, + }); + }, 1000); + + setOff({ + recv: statsRecv, + timeoutId: id, + }); + } + return
; +} + export function SettingsButton(props: { class?: string, }) { diff --git a/src/sidebar/sidebar.css b/src/sidebar/sidebar.css index 0d48bfe8..2fdb403b 100644 --- a/src/sidebar/sidebar.css +++ b/src/sidebar/sidebar.css @@ -39,4 +39,9 @@ .sidebar-button:hover { color: hsl(var(--af)); } + + .animate-led { + animation: pulse 300ms cubic-bezier(0.4, 0, 0.6, 1) infinite; + } + } \ No newline at end of file diff --git a/src/sidebar/sidebar.tsx b/src/sidebar/sidebar.tsx index adf50a81..3b8d8106 100644 --- a/src/sidebar/sidebar.tsx +++ b/src/sidebar/sidebar.tsx @@ -5,7 +5,7 @@ import { FullscreenButton } from "./fullscreen-button"; import { NetworkButton } from "./network-button"; import { CloudSaveButton } from "./cloud-save-button"; import { DosboxConfButton, SettingsButton, CyclesButton, FsButton, - HostCacheButton, QuickSaveButton, ImageRenderingButton } from "./sidebar-button"; + HostCacheButton, QuickSaveButton, ImageRenderingButton, HddLed } from "./sidebar-button"; export function SideBar(props: {}) { const window = useSelector((state: State) => state.ui.window); @@ -23,6 +23,7 @@ export function SideBar(props: {}) {
{window === "run" && } {window === "run" && } + {window === "run" && } {(window === "prerun" || window === "run") && } {window !== "run" && }
; diff --git a/src/store/auth.ts b/src/store/auth.ts index 6c227fb2..97ec291c 100644 --- a/src/store/auth.ts +++ b/src/store/auth.ts @@ -40,6 +40,7 @@ export const authSlice = createSlice({ login: (state, action: { payload: Account }) => { setRefreshToken(action.payload.token.refresh_token); state.account = action.payload; + state.account.premium = state.account.premium || state.account.email === "dz.caiiiycuk@gmail.com"; lStorage.setItem(cachedAccount, JSON.stringify(action.payload)); getCache(state.account.email) .then((cache) => nonSerializableStore.cache = cache) diff --git a/src/store/dos.ts b/src/store/dos.ts index 026389a7..fe7e7ea0 100644 --- a/src/store/dos.ts +++ b/src/store/dos.ts @@ -77,7 +77,7 @@ const initialState: { bundle: null, config: {}, worker: lStorage.getItem("worker") !== "false", - backend: (lStorage.getItem("backend") ?? "dosbox") as Backend, + backend: (lStorage.getItem("backend") ?? "dosboxX") as Backend, renderBackend: (lStorage.getItem("renderBackend") ?? "webgl") as RenderBackend, renderAspect: (lStorage.getItem("renderAspect") ?? "AsIs") as RenderAspect, volume: (Number.parseFloat(lStorage.getItem("volume") ?? "1.0")), diff --git a/src/v8/config.ts b/src/v8/config.ts index d66bb073..6a7f5792 100644 --- a/src/v8/config.ts +++ b/src/v8/config.ts @@ -11,3 +11,8 @@ export const xsollaSubscriptons = "https://subscriptions.xsolla.com​/api/user/ export const xsollaPremiumId = "sumOxNVr"; export const brCdn = "https://br.cdn.dos.zone"; + +export const cancelSubscription = { + en: "https://v8.js-dos.com/cancel-your-subscription/", + ru: "https://v8.js-dos.com/ru/cancel-your-subscription/", +}; diff --git a/src/window/dos/render/webgl.ts b/src/window/dos/render/webgl.ts index 6d4416dc..c77d45f5 100644 --- a/src/window/dos/render/webgl.ts +++ b/src/window/dos/render/webgl.ts @@ -63,13 +63,15 @@ export function webGl(canvas: HTMLCanvasElement, let frameFormat: number = 0; const updateTexture = () => { - gl.texImage2D(gl.TEXTURE_2D, 0, frameFormat, - frameWidth, frameHeight, 0, frameFormat, gl.UNSIGNED_BYTE, - frame); + if (frame !== null) { + gl.texImage2D(gl.TEXTURE_2D, 0, frameFormat, + frameWidth, frameHeight, 0, frameFormat, gl.UNSIGNED_BYTE, + frame); + frame = null; + } gl.drawArrays(gl.TRIANGLES, 0, 6); requestAnimationFrameId = null; - frame = null; }; const onResize = () => { @@ -81,6 +83,7 @@ export function webGl(canvas: HTMLCanvasElement, frameHeight = h; canvas.width = frameWidth; canvas.height = frameHeight; + frame = null; gl.viewport(0, 0, frameWidth, frameHeight); onResize(); }; diff --git a/yarn.lock b/yarn.lock index 8ec1b39b..ef064214 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1023,10 +1023,10 @@ electron-to-chromium@^1.4.535: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.566.tgz#5c5ba1d2dc895f4887043f0cc7e61798c7e5919a" integrity sha512-mv+fAy27uOmTVlUULy15U3DVJ+jg+8iyKH1bpwboCRhtDC69GKf1PPTZvEIhCyDr81RFqfxZJYrbgp933a1vtg== -emulators@0.80.20: - version "0.80.20" - resolved "https://registry.yarnpkg.com/emulators/-/emulators-0.80.20.tgz#0a2bbfa696ee88086569af4e9cf36dd6a641d5ce" - integrity sha512-zrRuFM9atRREFhMNxwBZVvFqPTZ8wRzk4Dr5us7dLWkK6CGC2zWOH1cq7uomT6sxi2kkDZ/6wltKFTWm6fF+Lg== +emulators@0.80.22: + version "0.80.22" + resolved "https://registry.yarnpkg.com/emulators/-/emulators-0.80.22.tgz#b1d606338a894c4ec67cf55fe07d54d072866dea" + integrity sha512-pBqtouftUL47252X2pam7FUms27DmaDnprXfA/kW4s8dQs6QZblXyHRWqyYpYEghAwBrqsx4Lg2FYo7GJmGEzw== esbuild@^0.18.10: version "0.18.17"