From 61dfa8e572cf21a613b23246780b369a9d7f6588 Mon Sep 17 00:00:00 2001 From: Gorbachev Egor <7gorbachevm@gmail.com> Date: Wed, 8 May 2024 19:24:36 +0700 Subject: [PATCH] Encapsulate language, start and client data into platform --- src/lib/platform/browser/browser-platform.ts | 14 +++++++ src/lib/platform/platform.ts | 7 +++- .../prevent-telegram-swipe-down-closing.tsx | 14 +++++-- .../platform/telegram/telegram-platform.ts | 38 +++++++++++++++++++ src/lib/request/collect-client-data.ts | 10 +---- src/screens/deck-list/main-screen.tsx | 3 +- src/store/deck-list-store.test.ts | 2 +- src/translations/get-user-language.ts | 14 ------- src/translations/t.ts | 4 +- src/ui/deck-category-logo.tsx | 6 ++- src/ui/input.tsx | 9 ++++- 11 files changed, 86 insertions(+), 35 deletions(-) delete mode 100644 src/translations/get-user-language.ts diff --git a/src/lib/platform/browser/browser-platform.ts b/src/lib/platform/browser/browser-platform.ts index c4bbe5b8..a8abc4e5 100644 --- a/src/lib/platform/browser/browser-platform.ts +++ b/src/lib/platform/browser/browser-platform.ts @@ -2,6 +2,8 @@ import { Platform, PlatformTheme } from "../platform.ts"; import { makeAutoObservable } from "mobx"; import { assert } from "../../typescript/assert.ts"; import { BooleanToggle } from "mobx-form-lite"; +import { PlatformSchemaType } from "../../../../functions/services/get-user.ts"; +import { Language } from "../../../translations/t.ts"; const cssVariables = { "--tg-theme-hint-color": "#999999", @@ -57,6 +59,18 @@ export class BrowserPlatform implements Platform { }; } + getLanguage(): Language { + return "en"; + } + + getStartParam(): string | undefined { + return undefined; + } + + getClientData(): PlatformSchemaType { + return {}; + } + showMainButton(text: string, onClick: () => void, condition?: () => boolean) { this.mainButtonInfo = { text, diff --git a/src/lib/platform/platform.ts b/src/lib/platform/platform.ts index ea0fcaed..e478cb9e 100644 --- a/src/lib/platform/platform.ts +++ b/src/lib/platform/platform.ts @@ -1,6 +1,8 @@ import { TelegramPlatform } from "./telegram/telegram-platform.ts"; import { BrowserPlatform } from "./browser/browser-platform.ts"; import { isRunningWithinTelegram } from "./is-running-within-telegram.ts"; +import { PlatformSchemaType } from "../../../functions/services/get-user.ts"; +import { Language } from "../../translations/t.ts"; export type PlatformTheme = { buttonColor: string; @@ -9,11 +11,14 @@ export type PlatformTheme = { }; export interface Platform { - getInitData(): string; initialize(): void; + getInitData(): string; openExternalLink(link: string): void; openInternalLink(link: string): void; getTheme(): PlatformTheme; + getClientData(): PlatformSchemaType; + getLanguage(): Language; + getStartParam(): string | undefined; } export type UseMainButtonType = ( diff --git a/src/lib/platform/telegram/prevent-telegram-swipe-down-closing.tsx b/src/lib/platform/telegram/prevent-telegram-swipe-down-closing.tsx index 70273ca5..ac6edba7 100644 --- a/src/lib/platform/telegram/prevent-telegram-swipe-down-closing.tsx +++ b/src/lib/platform/telegram/prevent-telegram-swipe-down-closing.tsx @@ -1,7 +1,9 @@ import React, { ReactNode, useEffect, useRef } from "react"; -import WebApp from "@twa-dev/sdk"; import { css } from "@emotion/css"; import { throttle } from "../../throttle/throttle.ts"; +import { platform } from "../platform.ts"; +import { TelegramPlatform } from "./telegram-platform.ts"; +import WebApp from "@twa-dev/sdk"; type Props = { condition: boolean; @@ -75,8 +77,9 @@ export const PreventTelegramSwipeDownClosing = (props: Props) => { export const PreventTelegramSwipeDownClosingIos = (props: { children: ReactNode; }) => { + const isEnabled = platform instanceof TelegramPlatform && platform.isIos(); return ( - + {props.children} ); @@ -85,9 +88,14 @@ export const PreventTelegramSwipeDownClosingIos = (props: { // A hacky way to force expand app back whenever user pull app down export const useRestoreFullScreenExpand = () => { useEffect(() => { - if (WebApp.platform !== "android" && WebApp.platform !== "ios") { + if (!(platform instanceof TelegramPlatform)) { + return; + } + + if (!platform.isIos() && !platform.isAndroid()) { return; } + const onViewPortChanged = () => { WebApp.expand(); }; diff --git a/src/lib/platform/telegram/telegram-platform.ts b/src/lib/platform/telegram/telegram-platform.ts index 0d833f2e..f4260da7 100644 --- a/src/lib/platform/telegram/telegram-platform.ts +++ b/src/lib/platform/telegram/telegram-platform.ts @@ -1,6 +1,8 @@ import WebApp from "@twa-dev/sdk"; import { Platform, PlatformTheme } from "../platform.ts"; import { cssVarToValue } from "./css-var-to-value.ts"; +import { PlatformSchemaType } from "../../../../functions/services/get-user.ts"; +import { Language } from "../../../translations/t.ts"; const buttonColor = "var(--tg-theme-button-color)"; const buttonTextColor = "var(--tg-theme-button-text-color)"; @@ -19,6 +21,10 @@ export class TelegramPlatform implements Platform { }; } + getStartParam(): string | undefined { + return WebApp.initDataUnsafe.start_param; + } + initialize() { WebApp.ready(); WebApp.setHeaderColor("secondary_bg_color"); @@ -37,6 +43,38 @@ export class TelegramPlatform implements Platform { WebApp.openTelegramLink(link); } + isIos() { + return WebApp.platform === "ios"; + } + + isAndroid() { + return WebApp.platform === "android"; + } + + getClientData(): PlatformSchemaType { + return { + platform: WebApp.platform, + colorScheme: WebApp.colorScheme, + tgVersion: WebApp.version, + }; + } + + getLanguage(): Language { + const languageCode = WebApp.initDataUnsafe.user?.language_code; + switch (languageCode) { + case "ru": + case "es": + case "pt-br": + return languageCode; + default: + return "en"; + } + } + + isTelegramDesktop() { + return WebApp.platform === "tdesktop"; + } + openExternalLink(link: string) { WebApp.openLink(link); } diff --git a/src/lib/request/collect-client-data.ts b/src/lib/request/collect-client-data.ts index a84c5319..17bde33c 100644 --- a/src/lib/request/collect-client-data.ts +++ b/src/lib/request/collect-client-data.ts @@ -1,14 +1,8 @@ -import WebApp from "@twa-dev/sdk"; -import { PlatformSchemaType } from "../../../functions/services/get-user.ts"; +import { platform } from "../platform/platform.ts"; export const collectClientData = () => { try { - const data: PlatformSchemaType = { - platform: WebApp.platform, - colorScheme: WebApp.colorScheme, - tgVersion: WebApp.version, - }; - + const data = platform.getClientData(); return JSON.stringify(data); } catch (e) { return ""; diff --git a/src/screens/deck-list/main-screen.tsx b/src/screens/deck-list/main-screen.tsx index 62d5fb88..fcf85967 100644 --- a/src/screens/deck-list/main-screen.tsx +++ b/src/screens/deck-list/main-screen.tsx @@ -10,7 +10,6 @@ import { theme } from "../../ui/theme.tsx"; import { screenStore } from "../../store/screen-store.ts"; import { Button } from "../../ui/button.tsx"; import { DeckLoading } from "../shared/deck-loading.tsx"; -import WebApp from "@twa-dev/sdk"; import { ListHeader } from "../../ui/list-header.tsx"; import { range } from "../../lib/array/range.ts"; import { reset } from "../../ui/reset.ts"; @@ -26,7 +25,7 @@ import { platform } from "../../lib/platform/platform.ts"; export const MainScreen = observer(() => { useMount(() => { - deckListStore.loadFirstTime(WebApp.initDataUnsafe.start_param); + deckListStore.loadFirstTime(platform.getStartParam()); }); return ( diff --git a/src/store/deck-list-store.test.ts b/src/store/deck-list-store.test.ts index 36203054..728b0d97 100644 --- a/src/store/deck-list-store.test.ts +++ b/src/store/deck-list-store.test.ts @@ -9,7 +9,7 @@ vi.mock("mobx-persist-store", () => { }; }); -vi.mock('./user-store.ts', () => { +vi.mock("./user-store.ts", () => { return { userStore: { myId: 111, diff --git a/src/translations/get-user-language.ts b/src/translations/get-user-language.ts deleted file mode 100644 index ba033089..00000000 --- a/src/translations/get-user-language.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Language } from "./t.ts"; -import WebApp from "@twa-dev/sdk"; - -export const getUserLanguage = (): Language => { - const languageCode = WebApp.initDataUnsafe.user?.language_code; - switch (languageCode) { - case "ru": - case "es": - case "pt-br": - return languageCode; - default: - return "en"; - } -}; diff --git a/src/translations/t.ts b/src/translations/t.ts index f51c8489..e61df774 100644 --- a/src/translations/t.ts +++ b/src/translations/t.ts @@ -1,5 +1,5 @@ import { Translator } from "../lib/translator/translator.ts"; -import { getUserLanguage } from "./get-user-language.ts"; +import { platform } from "../lib/platform/platform.ts"; const en = { folder_form_no_decks: "No decks in the folder", @@ -1010,7 +1010,7 @@ export const translateCategory = (category: string) => { export const translator = new Translator( translations, - getUserLanguage(), + platform.getLanguage(), ); export const t = (key: keyof Translation, defaultValue?: string) => { diff --git a/src/ui/deck-category-logo.tsx b/src/ui/deck-category-logo.tsx index 3018452b..ebd73dbd 100644 --- a/src/ui/deck-category-logo.tsx +++ b/src/ui/deck-category-logo.tsx @@ -1,7 +1,8 @@ import React from "react"; import { css } from "@emotion/css"; -import WebApp from "@twa-dev/sdk"; import { t, translateCategory } from "../translations/t.ts"; +import { platform } from "../lib/platform/platform.ts"; +import { TelegramPlatform } from "../lib/platform/telegram/telegram-platform.ts"; // Windows doesn't support flag emojis, so we replace them with images // TODO: move to database @@ -16,7 +17,8 @@ export const replaceFlagEmojiOnWindows = (logo: string) => { } }; -const supportsEmojiFlag = WebApp.platform !== "tdesktop"; +const supportsEmojiFlag = + platform instanceof TelegramPlatform ? !platform.isTelegramDesktop() : true; type Props = { logo: string; diff --git a/src/ui/input.tsx b/src/ui/input.tsx index 65cd2364..1901475f 100644 --- a/src/ui/input.tsx +++ b/src/ui/input.tsx @@ -5,7 +5,8 @@ import { TextField } from "mobx-form-lite"; import { observer } from "mobx-react-lite"; import autosize from "autosize"; import { ValidationError } from "./validation-error.tsx"; -import WebApp from "@twa-dev/sdk"; +import { platform } from "../lib/platform/platform.ts"; +import { TelegramPlatform } from "../lib/platform/telegram/telegram-platform.ts"; interface Props { placeholder?: string; @@ -32,7 +33,11 @@ export const Input = observer((props: Props) => { const Tag = type === "textarea" ? "textarea" : "input"; useEffect(() => { - if (type === "textarea" && inputRef.current && WebApp.platform !== "ios") { + if (platform instanceof TelegramPlatform && platform.isIos()) { + return; + } + + if (type === "textarea" && inputRef.current) { if (!noAutoSize) { autosize(inputRef.current); }