From 763d0cdfb11514a67b3c2427a105639f44585f07 Mon Sep 17 00:00:00 2001 From: Alexander Guryanov Date: Fri, 6 Sep 2024 11:37:48 +0300 Subject: [PATCH] v8.2.1: update sockdrive warnings --- src/frame/fat-drives-frame.tsx | 13 +++----- src/frame/stats-frame.tsx | 21 ++++++++++++- src/i18n.ts | 10 ++++-- src/player-api.ts | 13 +++++++- src/store/dos.ts | 5 +++ src/store/ui.ts | 2 +- src/ui.tsx | 57 +++++++++++++++++++++++++--------- src/window/dos/dos-runtime.tsx | 7 +++-- src/window/prerun-window.tsx | 7 +++-- 9 files changed, 102 insertions(+), 33 deletions(-) diff --git a/src/frame/fat-drives-frame.tsx b/src/frame/fat-drives-frame.tsx index 1258fc4f..7d0a3aaf 100644 --- a/src/frame/fat-drives-frame.tsx +++ b/src/frame/fat-drives-frame.tsx @@ -6,6 +6,7 @@ import { State } from "../store"; import { useEffect, useRef, useState } from "preact/hooks"; import { dispatchLoginAction, uiSlice } from "../store/ui"; import { LockBadge } from "../components/lock"; +import { isSockdrivePremium } from "../player-api"; interface Drive { name: string, @@ -94,15 +95,9 @@ export function FatDrivesFrame() { .catch(console.error) .finally(() => setBusy(false)); - fetch(sockdriveEndpoint + "/premium/" + account.email) - .then((r) => r.json()) - .then((payload: { premium: boolean }) => { - setSockdrivePremium(payload.premium); - }) - .catch((e) => { - console.error(e); - setSockdrivePremium(false); - }); + isSockdrivePremium(sockdriveEndpoint, account) + .then(setSockdrivePremium) + .catch(console.error); } } diff --git a/src/frame/stats-frame.tsx b/src/frame/stats-frame.tsx index f372d3e8..f54ee4e6 100644 --- a/src/frame/stats-frame.tsx +++ b/src/frame/stats-frame.tsx @@ -1,14 +1,23 @@ import { useSelector } from "react-redux"; -import { State } from "../store"; +import { State, useNonSerializableStore } from "../store"; export function StatsFrame() { + const nonSerializableStore = useNonSerializableStore(); + const backend = useSelector((state: State) => state.dos.backend); + const hardware = useSelector((state: State) => state.dos.backendHardware) && + nonSerializableStore.options.backendHardware; + const emuVersion = useSelector((state: State) => state.dos.emuVersion); const startedAt = useSelector((state: State) => state.dos.ciStartedAt); const stats = useSelector((state: State) => state.dos.stats); + const driveInfo = useSelector((state: State) => state.dos.sockdriveInfo); const cycles = Math.round(useSelector((state: State) => state.dos.stats.cyclesPerMs) / 1000); const driveRecvMb = Math.round(stats.driveRecv / 1024 / 1024 * 100) / 100; const driveSpeedMb = (stats.driveRecvTime / 1000) > 1 ? Math.round(driveRecvMb / stats.driveRecvTime * 1000 * 100) / 100 : 0; return
+
+ js-dos/emu: {JSDOS_VERSION}/{emuVersion} +
@@ -18,6 +27,10 @@ export function StatsFrame() { + + + + @@ -64,6 +77,12 @@ export function StatsFrame() { + {driveInfo.map((info, i) => { + return + + + ; + })} diff --git a/src/i18n.ts b/src/i18n.ts index 0219e7c3..d8ab38ae 100644 --- a/src/i18n.ts +++ b/src/i18n.ts @@ -15,6 +15,7 @@ const translations: {[lang: string]: {[key: string]: string} } = { add: "Добавить", logout: "Выйти", please_login: "Войдите в аккаунт", + login: "Войти", features: "Функции", premium: "Подписка", buy: "Купить", @@ -71,7 +72,7 @@ const translations: {[lang: string]: {[key: string]: string} } = { copy_net_link: "Отправьте ссылку на подключение", copied: "Скопировано", image_rendering: "Обработка изображения", - read_only_access: "Диск FAT32 открыт только для чтения", + read_only_access: "Эмуляция Win 9x в режиме только для чтения", fix: "Исправить", close: "Закрыть", cancle: "Отказаться", @@ -83,6 +84,8 @@ const translations: {[lang: string]: {[key: string]: string} } = { fat_write: "FAT запись", play: "Запустить", system_cursor: "Системный курсор", + no_cloud_access: "Войдите что бы использовать", + cloud_storage: "облачное хранилище", }, en: { play: "Start", @@ -98,6 +101,7 @@ const translations: {[lang: string]: {[key: string]: string} } = { add: "Add", logout: "Logout", please_login: "Please login", + login: "Login", features: "Features", premium: "Subscription", buy: "Buy", @@ -154,7 +158,7 @@ const translations: {[lang: string]: {[key: string]: string} } = { copy_net_link: "Share this link to connect", copied: "Copied", image_rendering: "Image rendering", - read_only_access: "The FAT32 drive is open in read-only mode", + read_only_access: "Win 9x emulation is in READ ONLY mode", fix: "Fix", close: "Close", cancle: "Cancle", @@ -164,6 +168,8 @@ const translations: {[lang: string]: {[key: string]: string} } = { hardware: "Hardware acceleration", net_drives: "Net drives", fat_write: "Writeable FAT", + no_cloud_access: "Please login to use", + cloud_storage: "cloud storage", }, }; diff --git a/src/player-api.ts b/src/player-api.ts index f2c46e73..550edf1f 100644 --- a/src/player-api.ts +++ b/src/player-api.ts @@ -3,6 +3,7 @@ import { NonSerializableStore, State } from "./store"; import { getT } from "./i18n"; import { putChanges } from "./v8/changes"; import { uiSlice } from "./store/ui"; +import { Account } from "./store/auth"; export async function apiSave(state: State, nonSerializableStore: NonSerializableStore, @@ -31,7 +32,7 @@ export async function apiSave(state: State, if (account === null || account.email === null) { dispatch(uiSlice.actions.showToast({ message: t("warn_save"), - intent: "warning", + intent: "success", })); } else { dispatch(uiSlice.actions.showToast({ @@ -51,3 +52,13 @@ export async function apiSave(state: State, return false; } } + +export function isSockdrivePremium(sockdriveEndpoint: string, account: Account | null): Promise { + if (account) { + return fetch(sockdriveEndpoint + "/premium/" + account.email) + .then((r) => r.json()) + .then((payload: { premium: boolean }) => payload.premium); + } else { + return Promise.resolve(false); + } +} diff --git a/src/store/dos.ts b/src/store/dos.ts index d9c01bb3..03de5020 100644 --- a/src/store/dos.ts +++ b/src/store/dos.ts @@ -77,6 +77,7 @@ const initialState: { }, imageRendering: ImageRendering, sockdriveWrite: boolean, + sockdriveInfo: { drive: string, write: boolean}[], softKeyboard: boolean, softKeyboardLayout: string[], softKeyboardSymbols: {[key: string]: string}[], @@ -129,6 +130,7 @@ const initialState: { ciStartedAt: 0, imageRendering: (lStorage.getItem("imageRendering") ?? "pixelated") as any, sockdriveWrite: true, + sockdriveInfo: [], softKeyboard: false, softKeyboardLayout: [ "{esc} ` 1 2 3 4 5 6 7 8 9 0 () - = {bksp} {enter}", @@ -312,6 +314,9 @@ export const dosSlice = createSlice({ setSockdriveWrite: (s, a: { payload: boolean }) => { s.sockdriveWrite = a.payload; }, + addSockdriveInfo: (s, a: { payload: { drive: string, write: boolean} }) => { + s.sockdriveInfo.push(a.payload); + }, mobileControls: (s, a: { payload: boolean }) => { s.mobileControls = a.payload; }, diff --git a/src/store/ui.ts b/src/store/ui.ts index b9be92b9..87d70ef7 100644 --- a/src/store/ui.ts +++ b/src/store/ui.ts @@ -51,7 +51,7 @@ const initialState: { toastIntent: "none", toastTimeoutId: 0, background: null, - readOnlyWarning: false, + readOnlyWarning: true, updateWsWarning: false, cloudSaves: true, autoStart: false, diff --git a/src/ui.tsx b/src/ui.tsx index 064131f5..32b51b93 100644 --- a/src/ui.tsx +++ b/src/ui.tsx @@ -1,4 +1,4 @@ -import { useEffect, useRef } from "preact/hooks"; +import { useEffect, useRef, useState } from "preact/hooks"; import { useDispatch, useSelector } from "react-redux"; import { Login } from "./login/login"; import { Frame } from "./frame/frame"; @@ -7,6 +7,8 @@ import { State } from "./store"; import { dispatchLoginAction, uiSlice } from "./store/ui"; import { Window } from "./window/window"; import { useT } from "./i18n"; +import { sockdriveBackend } from "./store/init"; +import { isSockdrivePremium } from "./player-api"; let currentWideScreen = uiSlice.getInitialState().wideScreen; export function Ui() { @@ -14,6 +16,7 @@ export function Ui() { const hidden = useSelector((state: State) => state.ui.hidden); const theme = useSelector((state: State) => state.ui.theme); const dispatch = useDispatch(); + const prerun = useSelector((state: State) => state.ui.window) === "prerun"; useEffect(() => { if (hidden || rootRef === null || rootRef.current === null) { @@ -53,7 +56,7 @@ export function Ui() { - + { prerun && } ; }; @@ -61,7 +64,6 @@ export function Ui() { function Toast() { const toast = useSelector((state: State) => state.ui.toast); const intent = useSelector((state: State) => state.ui.toastIntent); - const readOnlyWarning = useSelector((state: State) => state.ui.readOnlyWarning); const intentClass = intent === "panic" ? "error" : intent; if (toast === null) { @@ -82,7 +84,7 @@ function Toast() { d="M12 9v3.75m9-.75a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9 3.75h.008v.008H12v-.008Z" />; } - return
+ return
state.ui.kiosk); const readOnlyWarning = useSelector((state: State) => state.ui.readOnlyWarning); const account = useSelector((state: State) => state.auth.account); + const backend = useSelector((state: State) => state.dos.backend); const t = useT(); const dispatch = useDispatch(); + const { sockdriveEndpoint } = useSelector((state: State) => + sockdriveBackend[state.init.sockdriveBackendName] ?? + sockdriveBackend["js-dos"]); + const [sockdrivePremium, setSockdrivePremium] = useState(true); + const premium = (account?.premium ?? false) || sockdrivePremium; + + useEffect(() => { + isSockdrivePremium(sockdriveEndpoint, account) + .then(setSockdrivePremium); + }, [account?.token, sockdriveEndpoint]); - if (!readOnlyWarning) { + if (!readOnlyWarning || kiosk || + (account !== null && backend === "dosbox") || + premium) { return null; } - function fix() { + function close() { dispatch(uiSlice.actions.readOnlyWarning(false)); - dispatchLoginAction(account, dispatch); } - function close() { + function fix() { dispatch(uiSlice.actions.readOnlyWarning(false)); + if (account === null) { + dispatchLoginAction(account, dispatch); + } else { + window.open("https://js-dos.com/subscription.html", "_blank"); + } } - return
+ const text = account === null ? + <>{t("no_cloud_access")} + {t("cloud_storage")} + : <>{t("read_only_access")}; + + return
- + class="text-error shrink-0 w-7 h-7 mt-1" stroke="currentColor" stroke-width="1.5px"> + ; - {t("read_only_access")} + {text}
- +
diff --git a/src/window/dos/dos-runtime.tsx b/src/window/dos/dos-runtime.tsx index 4fd8a3d9..7c82a84d 100644 --- a/src/window/dos/dos-runtime.tsx +++ b/src/window/dos/dos-runtime.tsx @@ -46,9 +46,10 @@ function useLog(ci: CommandInterface): void { dispatch(uiSlice.actions.cloudSaves(false)); if (args[0]?.indexOf("write=") !== -1) { console.log("drive", drive, "config:", args[0]); - } - if (args[0]?.indexOf("write=false") !== -1) { - dispatch(uiSlice.actions.readOnlyWarning(true)); + dispatch(dosSlice.actions.addSockdriveInfo({ + drive, + write: args[0]?.indexOf("write=false") === -1, + })); } if (args[0]?.indexOf("preload=") !== -1) { const rest = Number.parseInt(args[0].substring(args[0].indexOf("preload=") + "preload=".length)); diff --git a/src/window/prerun-window.tsx b/src/window/prerun-window.tsx index d186bf5a..4992b304 100644 --- a/src/window/prerun-window.tsx +++ b/src/window/prerun-window.tsx @@ -12,8 +12,11 @@ export function PreRunWindow() { return
-
jsdos/emu version:  - {JSDOS_VERSION}/{emuVersion}
+
+ + js-{JSDOS_VERSION}/emu-{emuVersion.substring(0, emuVersion.indexOf(" "))} + +
; }
Emulation{backend + " " + (hardware ? "(WS)" : "(WA)")}
Uptime {Math.round((Date.now() - startedAt) / 100) / 10} sNet RECV/s {Math.round(stats.netRecv / 1024 * 100) / 100}Kb
HDD { i == 0 ? "C:" : "D:"}{info.drive} {info.write ? " RW" : " RO" }
HDD RECV/s {driveRecvMb}Mb (~{driveSpeedMb}Mb/s)